c学习笔记7构造与析构

本节知识点:1.c++中的构造函数:

a.c++中的类可以定义与类名相同的特殊成员函数,这种与类名相同的成员函数叫做构造函数。构造函数在定义的时候可以有参数,但是没有任何返回类型的声明。

b.在c++编译器中,在类定义对象的时候就会顺便自动调用这个对象的构造函数,有时候也需要手动调用,代码如下:

#includestdio.hclasslist{private:  inta;  intb;  intc;public:  list(intv)  {    a=b=c=v;  }  voidlist_printf()  {    printf(%d%d%d\n,a,b,c);  }};intmain(){  listl(5);//自动调用方式一  listd=6;//自动调用方式二  listp=list(7);//手动调用  l.list_printf();  d.list_printf();  p.list_printf();    listar[3]={1,2,3};//对于类数组只能这样手动调用了  listar1[3]={(1),(2),(3)};  listar2[3]={list(1),list(2),list(3)};    return0;}

注意:上面定义类的三种方式c.类的成员函数和普通函数一样都可以进行重载,也就是说构造函数支持重载,代码如下:

#includestdio.hclasslist{private:  inta;  intb;  intc;public:  list()  {    a=1;    b=2;    c=3;    printf(list\n);  }  list(intv)  {    a=b=c=v;  }  voidlist_printf()  {    printf(%d%d%d\n,a,b,c);  }};intmain(){  lista=list();//无参数的构造函数的调用  lista1;//与上面语句等效切记lista1();是错误的~~~    listl(5);//自动调用方式一  listd=6;//自动调用方式二  listp=list(7);//手动调用  l.list_printf();  d.list_printf();  p.list_printf();    listar[3]={1,2,3};//对于类数组只能这样手动调用了  listar1[3]={(1),(2),(3)};  listar2[3]={list(1),list(2),list(3)};    return0;}

d.两个特殊的构造函数:无参构造函数:当类中没有定义构造函数时,编译器会默认提供一个无参构造函数,并且其函数体为空。其目的主要是为了,兼容那些没有定义构造函数的类的定义(因为我们知道定义类的时候,编译器会自动调用构造函数的),没有太多的实用价值。但是注意:第一可以自己定义无参构造函数,来代替编译器提供的那个函数,此时函数体就不再是空函数了。第二,没有构造函数的类的定义方式lista;或者lista=list();切记lista();是错误的方式!!!

拷贝构造函数:拷贝构造函数其实是一个参数为自己类的引用的构造函数,如:list(constlistl);当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,简单的进行成员变量的值的复制(默认的这个函数的功能是lista=b;把b类中的成员变量的值复制给a类中的成员变量,注意ab必须是同一个类)。但是你也可以自己定义拷贝构造函数,此时的函数功能就由你自己定了!!!

示例代码:

#includestdio.hclasslist{private:  inta;  intb;  intc;public:  list()  {    a=1;    b=2;    c=3;    printf(list\n);  }  list(intz)  {    a=b=c=z;  }  voidlist_printf()  {    printf(%d%d%d\n,a,b,c);  }  list(constlistr)//可以屏蔽这个函数看默认拷贝构造函数的功能  {    printf(copyhello\n);  }};intmain(){  lista=list();//无参数的构造函数的调用  lista1;//与上面语句等效切记lista1();是错误的~~~  listp(6);  listq=p;  q.list_printf();  return0;}

注意:1.当类中没有定义任何一个构造函数,c++编译器会提供无参构造函数和拷贝构造函数

2.当类中定义了任意的非拷贝构造函数时,c++编译器就不会提供无参构造函数

3.这里说下无参构造函数、有参构造函数、拷贝构造函数,他们的关系是重载的关系,在定义一个类的时候只能自动调用他们三者中的一个构造函数,选择方

式是根据定义方式来说的。

2.c++类中的初始化列表:

a.在类中的成员变量定义的时候,有些成员变量是需要赋初值的。比如说:const属性的只读变量、引用、只有有参构造函数的类。当存在这些不赋初值就报错的情况,而且类中的成员变量不能直接赋初值的时候,就需要用到初始化列表了。

b.初始化列表是写在构造函数后面,执行在构造函数前面,对类的成员变量进行初始化的语句,代码如下:

#includestdio.hclassM{private:intmI;public:M(inti){printf(M(inti),i=%d\n,i);mI=i;}intgetI(){returnmI;}};classTest{private:constintc;Mm1;Mm2;public:Test():c(1),m2(3),m1(2)//初始化列表中成员变量一个都不能少{printf(Test()\n);}Test(intz):c(10),m2(30),m1(20){    printf(Testint\n);}voidprint(){printf(c=%d,m1.mI=%d,m2.mI=%d\n,c,m1.getI(),m2.getI());}};intmain(){Testt1(2);t1.print();getchar();return0;}

针对上面的代码要注意几点:

第一:初始化列表是写在各个构造函数的后面的,切记成员变量一个都不能少否则编译出错,初始化列表是在构造函数执行之前执行的,成员变量的初始化顺序与在类中声明的顺序有关,与在初始化列表中的顺序无关。

第二:这个问题很重要,是关于c++中类的对象的赋值的问题,对于一个已经初始化完成的类的对象Testt1;可以进行t1=10;的操作,此时调用t1的Test(inta)构造函数,但是要注意的是,如果有初始化列表,虽然t1的成员变量的值发生了变化,但是这个过程不再是初始化了,而是直接对t1的成员变量根据初始化列表中的值进行赋值操作。可以用constintc;这个只读变量来判断,如果这个过程是初始化,c这个成员变量是可以编译通过的,但是这个过程是赋值过程,c又是const属性,所以编译会出错!!!同时对于t1还可以进行t1=t2;的操作,这个过程即没有调用有参构造函数,也没有调用拷贝构造函数。是简简单单的把t2的成员变量的值,赋值给t1的成员变量中去!!!但是如果Testt1是一个函数的形参voidfun(Testt1),当调用这个函数的时候fun(t2);,t2当做实参,此时调用了拷贝构造函数!!!

第三:类中的const成员变量时肯定会被分配空间的,只是一个只读变量,因为编译器无法直接得到const成员变量的初始值,因此无法进入符号表成为真正的常量。

第四:初始化与赋值是不同的,这个是在补充第二点,初始化是用已存在的对象或值对正在创建的对象进行初值设置。赋值是用已存在的对象或值对已经存在的对象进行值的设置。

3.c++中的析构函数:

a.c++中在对象撤销的时候,对象会自动调用一个清理函数,与构造函数相对应,叫析构函数。析构函数为~classname(),且没有参数也没有任何返回值类型。

示例代码:

#includestdio.hclassTest{private:intmI;public:Test(inti):mI(i){printf(Test(),mI=%d\n,mI);}~Test(){printf(~Test(),mI=%d\n,mI);}};voidrun(){Testt1(1);Testt2(2);}intmain(){run();printf(Pressanykeytocontinue...);getchar();return0;}

注意:析构函数的调用顺序!!!

通过上面的例子,我们发现析构函数的调用顺序是与构造函数的调用顺序完全相反的!!!那我们总结下构造函数的调用顺序:

第一:当类中有成员变量是其他类的对象时,首先调用成员变量的构造函数。(注:调用顺序与声明顺序相同)

第二:调用自身类的构造函数。

4.构造函数与析构函数的关系:

第一点:构造函数与析构函数的产生都是因为,他们可以自动调用(省事),构造函数是类创建对象的时候自动调用的,析构函数是对象销毁的时候自动调用的。

第二点:在某些情况下,c++编译器可以提供默认的构造函数(即无参构造函数和拷贝构造函数),但是析构函数则需要程序员自己手写,编译器提供不了。

第三点:构造函数与析构函数的调用顺序是完全相反的。

课后练习:1.可以直接调用构造函数吗?

在这里多说几句,首先说说这个问题,这个问题的含义是在main函数或者类的成员函数中,可不可以不通过对象直接调用test();这个构造函数,结果是可以编译通过。但是没有对象就直接调用对象里面的成员函数,这也太荒唐了!!!所以编译器此时让构造函数得到了一个临时对象,导致这个构造函数完成不了任何功能!!!这里还要声明一个问题,就是通过对象来访问对象的构造函数是编译出错的,原因未知!!!总之这个问题有些无趣,荒谬。给个小例子附在后面(可以不看):

#includestdio.hclassTest{private:intmI;intmJ;constchar*mS;public:Test(){printf(Test()\n);mI=0;mJ=0;}Test(constchar*s){printf(Test(constchar*s)\n);Test();mS=s;}~Test(){printf(~Test()\n);}voidprint(){printf(mI=%d,mJ=%d,mS=%s\n,mI,mJ,mS);}};voidrun(){Testt=Test(helloworld);//Testt(helloworld);t.print();}intmain(){run();//Testa;//a.Test();getchar();return0;}

如果您对“猿来如此”团队有什么建议,或想了解哪家公司的哪个岗位,亦或是想了解哪项技术,请私信我们,我们会尽最大的努力来帮您解答您的问题!

想了解更多关于“猿来如此”的信息,







































北京治疗白癜风哪家技术好
北京治疗白癜风会痛吗



转载请注明:http://www.nydjfy.com/xxzl/910.html