6 构造函数
构造函数作用:分配空间,初始化变量。实例的对象在初始化时只保证实参传递到构造函数里面,不保证传到成员变量里,所以在构造函数里要手动把实参赋值给成员变量 ;构造函数可以重载;自动调用;可以有默认值,如果没有系统可以自动给构造一个,但是不提供复制操作; 只执行一次;一般来初始化成员;只要自己定义了构造函数,编译器不再产生构造函数。
注意:构造无参对象时不要使用Class name()而是Class name,应为括号会使编译器误以为函数声明。
6.1 初始化列表
为成员变量专门初始化 ,在构造函数参数表后面
格式:成员变量名(初始化值),初始化变量名(初始值)
6.2 拷贝构造函数
三种情况会调用拷贝构造函数:
1.用一个类的对象去初始化该类的另一个对象时
2.函数的形参是类的对象,实参初始化形参(1)
3.函数的返回值是对象的引用,此时就会调用拷贝构造函数,将此对象复制 给一个临时对象并传到该函数的调用处(1)
提示:尽量使用const修饰的形参,返回值,避免多余的开销和对复制构造函数的调用
6.3 赋值构造函数
复制构造函数即重载“=”操作符函数,与拷贝构造函数的区别是:拷贝构造函数用于初始化,而赋值构造函数则必须是对已存在对象的重新复制。
6.4 拷贝构造函数形参必为引用类型
若为值传递,就会引起循环调用拷贝构造函数(形参都是由实参初始化,此处实为用类的对象初始化类,即拷贝);形参中有自定义类的类型,最好也是引用类型
6.5 深拷贝与浅拷贝
在默认拷贝构造函数和赋值构造函数中,拷贝的策略是逐个成员依次拷贝,但是,一个类可会拥有资源,如果拷贝构造函数,简单地制作了一个该资源的拷贝(指针),而不对它本身分配(默认拷贝/赋值构造函数的行为:浅拷贝),就得面临一个麻烦的局面:两个对象都拥有同一个资源。当对象析构时,该资源将经历两次资源返还。
6.6 this指针
对象调用成员函数时实际也传递了一个对象本身地址的参数,而被调用的成员函数也隐藏一个参数 ,就是this指针,用来接收对象指针
#include<iostream>
#include<string>
using namespace std;
typedef unsigned int unint;
enum gender {F,M};
class Person
{
string name;
unint age;
gender g;
char *ch;
public:
Person(string name,unint age,gender g);
Person(const Person &p);
Person& operator=(const Person &p);
~Person();
void show();
};
Person::Person(string name,unint age,gender g)
{
(*this).name = name;
this->age = age;
Person::g = g;
ch = new char[age] ;
cout << this->name << "构造函数!"<< endl;
}
Person::Person(const Person &p)
{
name = p.name;
age = p.age;
g = p.g;
ch = new char[p.age]; //深拷贝
cout << this->name << "拷贝构造函数" << endl;
}
Person& Person::operator=(const Person &p)
{
if((&p) == this) return (*this);
name = p.name;
age = p.age;
g = p.g;
ch = p.ch; //浅拷贝
cout << this->name << "赋值函数!" << endl;
return (*this);
}
Person::~Person()
{
delete[] ch;
//ch = 0;
cout << this->name <<"析构函数" << endl;
}
void Person::show()
{
cout << static_cast<void*>(this->ch) << endl;
}
int main()
{
Person A("小明",18,F);
Person B(A); //复制构造
Person C("小红",28,M);
C = A;
A.show();
B.show();
C.show();
return 0;
}
注意:赋值函数采用了浅复制,但是析构的时候却没有报错,为什么呢?
解决方案:1.可以设置全局变量,在构造,拷贝构造,赋值函数中自增,析构时自减,当变量为零时释放内存。
2.重载复制构造函数,将指针指向新的内存分配间。