构造函数 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"<<endl;}
CSample(int n){ x = n;
cout<<"Constructor 2 called"<<endl;}
};
int main(){
CSample array1[2]; //定义了一个 对象数组array 1,这个数组里面有两个元素。
// 每个元素都是CSample对象
//这两个对象初始化的时候所用的参数没有做任何交代,
//编译器就认为 这个对象应该是用无参的构造函数初始化的。
cout<<"step 1"<<endl;
CSample array2[2] = {4,5};
cout<<"step 2"<<endl;
CSample array3[2] = {3};
cout<<"step 3"<<endl;
CSample *array4 = new CSample[2];
//动态分配了一个数组,这个数组里边有两个 对象,
//这两个对象如何初始化呢,我们对参数没有做任何交代
//那这么两个对象都是用无参的构造函数 初始化的
delete []array4;
return 0;
}
输出:

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"<<endl;
}
};
void Func(A a1){}
int main(){
A a2;
Func(a2);
return 0;
}

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"<<endl;
}
};
A Func(){
A b(4); //定义局部对象b
return b
}
int main(){
cout<<Func().v<<endl;} //

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

  1. 为什么要写自己的复制构造函数?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 书店一蹋进门我就小心翼翼翼地微踮着脚走进,免得高跟鞋的声音过于刺耳。噔噔得高跟鞋在安静的环境...
    就要马甲线阅读 163评论 0 0
  • 样例给出一个链表1->2->3->null,这个翻转后的链表为3->2->1->null 复制链表节点,一个一个放...
    和蔼的zhxing阅读 326评论 0 0
  • 谝故事是老碗会上最热闹的一项内容,也是这些大老粗里比较文雅的一件事。一人说,众人听,会场安静,秩序井然。 故事来取...
    泰山寒梅阅读 777评论 0 12