C++:构造函数与析构函数

构造函数

类的对象都是由构造函数产生的
同 Java 一样,若类未定义构造函数,则会产生默认构造函数(无参构造函数)

class complex{
	private:
		double real, image;
	public:
		complex(){}
		complex(double r){ real = r; image = 0; }
		complex(double r, double i){  }
		complex(complex c1, complex c2){
			real = c1.real + c2.real;
			image = c1.image + c2.image;
		}
};

构造函数可以使用初始化列表简写

complex (double r, double i) : real(r), image(i){}//用r初始化real,用i初始化image

构造函数的调用

complex c1;//complex()
complex c2();//complex()
complex c3(5);//complex(5)
complex *c4p = new complex(5, 6);//complex(5, 6)

complex cs1[3] = {1, complex(3,2) };
//cs1[0] -> complex(1) cs1[1] -> complex(3, 2) cs1[2] -> complex()

complex *csp1[2] = new complex[2];//均调用无参构造函数

complex *csp2[2] = {};//未创建任何对象

complex *csp3[3] = {new complex(1), new complex()};
//指针数组,前两个元素使用complex(1)、complex(),最后一个指针未初始化,仅创建了两个对象

复制构造函数

一个类一定有且仅有一个复制构造函数
形如 X::X(X &x)X::X(const X &x),参数必须是引用类型
若未自定义复制构造函数,编译器自动添加默认的构造函数
构造函数的作用类似 Java 中 Object.clone()

作用场景

  • 用一个对象去初始化同类的另一个对象时
    Complex c2(c1);
    Complex c2 = c1;(因为是声明语句,所以调用了复制构造函数)
  • 如果某个函数的参数为类对象,该函数调用时将使用复制构造函数初始化该参数
  • 当函数的返回值是一个类的对象时,返回的对象是通过以函数返回的对象作为参数
    调用复制构造函数产生的(无法返回一个局部变量)

对象间的赋值,并不会调用复制构造函数

此外,为避免调用复制构造函数初始化形参的开销,在合适的时候使用引用及引用常量类型的参数


转换构造函数

只有一个参数且不是复制构造函数的构造函数,一般可视作转换构造函数
在需要的时候,编译系统会自动调用转换构造函数,制造一个无名的临时对象

临时对象就是不可见的匿名对象,也叫无名对象,没有名字故无法继续使用
仅在运行中需要时生成,使用后析构

临时对象在 “full expression” 结束时被析构,即 生成临时对象的最大表达式结束处即是临时对象的析构处

complex::complex(double r){ real = r; image = 0;}//double型转换为complex类型
complex c = 5;//complex(5)
c = 9;//调用complex(9)
complex c2(3);//complex(3)

转换构造函数的作用是实现类型的转换,分为隐式转换和显式转换
上面 c = 9即为隐式转换
使用 explicit 关键字表明禁止其修饰的构造函数进行隐式的类型转换

c = complex(9);//函数仍然可以显式调用

隐式转换常常会导致迷惑行为,需要小心使用

string str = 'a';//实际上调用的是 string(int size), 可能误以为调用了string(char c)等

析构函数

名字与类名相同,在函数名前加 ~,一个类最多只有一个析构函数
编译器默认生成空实现的析构函数
每个对象消亡前自动调用析构函数,在对象结束生命周期前做善后工作,如释放资源

使用 delete 时、数组元素、局部对象消亡时也会调用析构函数,

class String{
	char *p;
	public:
		complex(size_t size){ p = new char[size]; }
		~ complex(){ delete [] p; }	
}

构造函数与析构函数调用示例

在这里插入图片描述


封闭类

成员变量中有类对象时,该类称为封闭类(enclosing)

对于封闭类,默认构造函数不可用,因为没有说明成员对象如何构造
因此必须使用有初始化列表说明成员对象如何构造的构造函数

封闭类的构造函数调用时,成员对象按照类的声明顺序
按照初始化列表调用相应的构造函数,或者使用默认构造函数 依次构造

封闭类的析构函数调用后,会依次调用成员对象的析构函数,次序与构造函数相反
在这里插入图片描述
当使用封闭类的默认复制构造函数时,其默认实现使用复制构造函数初始化成员对象
在这里插入图片描述
当然,如果自定义复制构造函数,可以使用初始化列表指定成员对象的构造方式


2020/1/17

posted @ 2020-01-17 01:06  kafm  阅读(101)  评论(0编辑  收藏  举报