构造函数 constructor和复制构造函数 copy constructor

注:以下大部分内容来源于 coursera 课程《C++程序设计》

构造函数

成员函数的一种,有以下特点:

  1. 名字与类名相同,可以有参数,但是不能有返回值(void也不行)。
  2. 作用:给对象进行初始化。这样就不需要写初始化函数和调用初始化,它会自动被调用。
  3. 如果没有写构造函数,编译器会生成默认的构造函数。
  4. 对象生成时构造函数自动被调用。
class Complex{
private:double real,imag;
public :
Complex(double r, double i=0);
};
Complex::Complex(double r, double i)
{
real = r; 
imag = i;
}
Complex r2;//报错,构造函数需要初始化,没有给参数,所以没法初始化,出错
Complex r2(0);//正确,第二个参数可以缺省
  1. 可以有多个构造函数,参数个数和参数类型都可以不同。这些构造函数是重载的关系。调用时根据参数个数和类型自动匹配。
class Complex{
private:double real,imag;
public :
Complex(double r, double i=0);
Complex(double r);
Complex(Complex c1,Complex c2);
};
Complex::Complex(double r, double i)
{
real = r; 
imag = i;
}
Complex::Complex(double r)
{
real = r; 
imag = 0;
}
Complex::Complex(Complex c1,Complex c2)
{
real = c1.real+c2.real; 
imag = c1.imag+c2.imag;
}
Complex c1(3);
Complex c2(0,5);
Complex c3(c1,c2);

  1. 构造函数在数组中的使用
    例子1:
class CSample{
int x;
public:
CSample(){cout<<"Constructor 1 called"<
输出:

Constructor 1 called
Constructor 1 called
step 1
Constructor 2 called
Constructor 2 called
step 2
Constructor 2 called
Constructor 1 called
step3
Constructor 1 called
Constructor 1 called

例子2:

class Test{
public:
Test(int n){}; //(1)
Test(int n, int m){};//(2)
Test(){}//(3)
};
Test array1[3] = {1,Test(1,2)} //(1)(2)(3)
Test array2[3] = {Test(2,3),Test(1,2),1} //(2)(2)(1)
Test *pArray2[3] = {new Test(4),new Test(1,2)} //(1)(2)(3)
//

难点:
Test *pArray2[3] = {new Test(4),new Test(1,2)} //(1)(2)(3)定义了这样的一个pArray数组,会不会导致对象生成,会不会引发test的构造函数被调用?
不会,因为这是一个指针数组,它里面的每一个元素都是一个指针,不是一个对象,不会引发任何对象的生成,这个指针可以不初始化的。现在对这个指针数组进行了初始化,而且对它的前两个元素进行 了初始化:new出来两个对象,这个new这个表达式的返回值是指针test *。
所以使用new出来的对象的地址去初始化这个数组里面的元素。

这条语句一共生成了几个对象?
生成了2个对象,而不是3个,为什么呀?因为pArray2的最后这个元素, 我们没有初始化,没有初始化它的话呢,它只不过是一个指针,而且也不知道指向哪,pArray2这个元素生成并不会导致任何对象的生成,所以这条语句, 只是生成了两个对象,这两个对象呢,分别用1,2进行初始化,这个 pArray2呢这个元素,它就是一个未经初始化的指针。

复制构造函数

  1. 格式:
X::X(X&)
X::X(const X&)

只有一个参数,即对同类对象的引用。

  1. 如果没有写,编译器会默认生成。这时候主要完成复制工作。
class Complex{
private:
double real, double imag;
};
Complex c1;//调用缺省的无参构造函数
Complex c1(c2);//调用缺省的复制构造函数,将c2复制给c1,c1与c2完全相等。

这里编译器会生成至少两个构造函数,一个是无参构造函数,一个是复制构造函数。

  1. 也可以定义自己的复制构造函数,这时候的功能
class Complex{
private:
double real, double imag;
Complex(){}
Complex(Complex &c){
real = c.real;
imag = c.imag;
cout<<"Copy Constructor called";

}
};
Complex c1;//
Complex c1(c2);//

c2这个对象就是用复制构造函数初始化的。

  1. 复制构造函数的三种作用:
    1) 用一个对象去初始化同类的另一个对象
Complex c2(c1)
Complex c2 = c1//初始化语句
c2 = c1//赋值

2)如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。

class A{
public:
A(){};
A(A&a){// 复制构造函数
cout<<"Copy Constructor called"<

void Func(A a1){}函数,形参是类A的对象,如果进到这个函数里面,形参就会被生成。这个形参是用什么构造函数初始化的呢?用复制构造函数初始化的。复制构造函数的时候是需要参数的,这个参数就是a2。
也就是说,形参a1是用复制构造函数初始化的,初始化a1的时候,那个复制构造函数的参数就是实参a2。
以前说过,一个函数的形参和实参是相等的。那么这里,形参a1的值还会等于实参a2吗?不一定。因为a1是用自己编写的复制构造函数去初始化的,这里这个函数并没有做复制的工作,而而仅仅是输出Copy Constructor called。
3) 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数将被调用。

class A{
public:
int v;
A(int n){v = n};
A(const A&a){ // 复制构造函数
v = a.v;
cout<<"Copy Constructor called"<

函数Func()的返回值类A,是一个class A的对象,在生成这个对象的时候,调用了复制构造函数初始化。
这儿复制构造函数进行了赋值工作,所以在 return b执行完了以后,作为返回值存在的这个对象被初始化,它的值和b一模一样。
这个函数的返回值一定就跟这个b相等吗? 那不一定了。就取决于你这个复制构造函数是怎么写的了。 因为这个函数的返回值是用复制构造函数初始化的,所以你那个复制构造函数里面如果没有执行复制的工作, 那么这个返回值的对象它的值当然就未必跟这个b相等了。

  1. 为什么要写自己的复制构造函数?

你可能感兴趣的:(构造函数 constructor和复制构造函数 copy constructor)