构造函数

  接着上一节,今天讲C++中类的构造函数与析构函数,对象的赋值与复制.

  1.用过C#语言的人,都知道构造函数是一种特殊的成员函数,它主要用于对对象分配空间,进行初始化。构造函数的名字必须与类名相同。可以有任何类型的参数,但不返回任何值,是在建立对象时自动执行的。和上一节一样,还是用Kid类来说明。

复制代码
 1 class Kid
 2 {
 3 private:
 4 int age;
 5 char*name;
 6 char*sex;
 7 public:
 8         Kid(int age,char*name,char*sex);
 9 void showKid();
10 };
11 
12 Kid::Kid(int age,char*name,char*sex)
13 {
14     Kid::age=age;
15     Kid::name=name;
16     Kid::sex=sex;
17 }
18 
19 void Kid::showKid()
20 {
21     cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
22 }
复制代码

  接下来,建立对象并初始化:Kid kid(10,"rookie_j","男");另外一种使用new运算符动态建立对象:Kid *ptr=new Kid(10,"rookie_j","男");通过指针变量ptr来访问:ptr->showKid();当我们用new建立对象时,当不再使用它时,要用delete运算符释放它:delete ptr;和不同成员函数一样,如果构造函数定义在类体内部,则作为内联函数处理;

  在声明类时,对数据成员的初始化一般在构造函数中用赋值语句进行,但C++还提供了另外一种初始化数据成员的方法——用成员初始化表来实现对数据成员的初始化。它的一般形式为:类名::构造函数名([参数表]):[(成员初始化表)];成员初始化表的形式为:成员名1(初始值1),成员名2(初始值2),成员名2(初始值2);比如:

Kid::Kid(int age,char *name,char *sex):age(age),name(name),sex(sex){};

  接下来讲一下析构函数:在我第一次在C++里看到这个名词时,感觉这个知识点很深奥,结果看了以后,其实很简单。它的作用和构造函数刚好相反,用于撤销对象,如:释放分配给对象的内存空间。析构函数和构造函数名相同,但在其前面要加~符号,析构函数没有参数,也没有返回值,且不能重载,因此一个类中只有一个析构函数。以下三种情况,当对象的生命周期结束时,析构函数会被自动调用:(1)定义了全局对象,则在程序流程离开其作用域(如:main函数结束或调用Exit)时,调用该全局对象的析构函数;(2)对象被定义在函数体里,则当这个函数执行完后,该对象释放,析构函数被自动调用;(3)若一个对象使用new运算符动态创建的,在使用delete运算符释放它时,会自动调用析构函数;

View Code
 1 #include "stdafx.h"
 2 #include <iostream>
 3 
 4 usingnamespace std;
 5 
 6 class Kid
 7 {
 8 private:
 9 int age;
10 char*name;
11 char*sex;
12 public:
13         Kid(int age,char*name,char*sex);
14 ~Kid();
15 void showKid();
16 };
17 
18 
19 Kid::Kid(int age,char*name,char*sex)
20 {
21     Kid::age=age;
22     Kid::name=newchar[strlen(name)];
23     strcpy(Kid::name,name);
24     Kid::sex=newchar[strlen(sex)];
25     strcpy(Kid::sex,sex);
26 }
27 
28 Kid::~Kid()
29 {
30     cout<<"dispose object kid"<<endl;
31     delete []name;
32     delete []sex;
33 }
34 
35 void Kid::showKid()
36 {
37     cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
38 }
39 
40 
41 int main()
42 {
43     Kid kid(10,"rookie_j","");
44     kid.showKid();
45 
46     Kid *ptr=new Kid(10,"rookie_x","");
47     ptr->showKid();
48 
49     delete ptr;
50 
51 return0;
52 }

结果:

  如果没有给类定义构造函数,则编译系统自动地生成一个默认的构造函数,比如在Kid类中编译系统会为其产生一个Kid::Kid(){};构造函数,这个默认的构造函数只能给对象开辟存储空间,不能给数据成员赋值,这时数据成员的初值就是随机数。对没有定义构造函数的类,其公有数据成员可以用初始化值表进行初始化,如:

复制代码
 1 class Kid
 2 {
 3 public:
 4 int age;
 5 char*name;
 6 char*sex;
 7 };
 8 
 9 int main()
10 {
11 
12     Kid kid={10,"Rookie_j",""};
13     cout<<"姓名:"<<kid.name<<endl<<"年龄:"<<kid.age<<endl<<"性别:"<<kid.sex<<endl;
14 
15 return0;
16 }
复制代码

但只要一个类定义了构造函数,系统将不再给它提供默认构造函数;另外还有默认的析构函数(Kid::~Kid(){})一般来说默认的析构函数就能满足要求,但对一些需要做一些内部处理的则应该显式定义析构函数。带默认参数的构造函数和之前所说的带参数的成员函数是一样的,对于构造函数的重载,在这里我就不多说了,只想强调一点,如果是无参的构造函数创建对象,应该使用"类名 对象名"的形式,而不是"类名 对象名()";

  2.对象的赋值其实和变量的赋值差不多,也是用赋值运算符=进行的,只不过进行赋值的两个对象的类型必须相同,对象之间的赋值只是数据成员的赋值,而不对成员函数赋值;

View Code
 1 #include "stdafx.h"
 2 #include <iostream>
 3 
 4 usingnamespace std;
 5 
 6 class Kid
 7 {
 8 private:
 9 int age;
10 char*name;
11 char*sex;
12 public:
13         Kid(int age,char*name,char*sex);
14         Kid(){    };
15 ~Kid();
16 void showKid();
17 };
18 
19 
20 Kid::Kid(int age,char*name,char*sex)
21 {
22     Kid::age=age;
23     Kid::name=newchar[strlen(name)];
24     strcpy(Kid::name,name);
25     Kid::sex=newchar[strlen(sex)];
26     strcpy(Kid::sex,sex);
27 }
28 
29 Kid::~Kid()
30 {
31     cout<<"dispose object kid"<<endl;
32     delete []name;
33     delete []sex;
34 }
35 
36 void Kid::showKid()
37 {
38     cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
39 }
40 
41 int main()
42 {
43     Kid kid(10,"rookie_j",""),kid2;
44     kid.showKid();
45 
46     kid2=kid;
47     kid2.showKid();
48 
49 return0;
50 }

结果:

  拷贝构造函数是一种特殊的构造函数,其形参是类对象的引用。它主要用于在建立一个新的对象时,使用已经存在的对象去初始化这个新对象。拷贝构造函数也是构造函数,所以函数名必须与类名相同,参数只有一个就是同类对象的引用,每个类必须要有一个拷贝构造函数。如果程序员自己不定义拷贝构造函数,系统会自动产生一个默认拷贝构造函数。调用拷贝构造函数的形式有代入法:类名 对象2(对象1)和赋值法:类名 对象2=对象1;

View Code
 1 #include "stdafx.h"
 2 #include <iostream>
 3 
 4 usingnamespace std;
 5 
 6 class Kid
 7 {
 8 private:
 9 int age;
10 char*name;
11 char*sex;
12 public:
13         Kid(int age,char*name,char*sex);
14         Kid(const Kid &kid);
15 ~Kid();
16 void showKid();
17 };
18 
19 
20 Kid::Kid(int age,char*name,char*sex)
21 {
22     Kid::age=age;
23     Kid::name=newchar[strlen(name)];
24     strcpy(Kid::name,name);
25     Kid::sex=newchar[strlen(sex)];
26     strcpy(Kid::sex,sex);
27 }
28 
29 Kid::Kid(const Kid &kid)
30 {
31     Kid::age=kid.age*2;
32     Kid::name=newchar[strlen(kid.name)];
33     strcpy(Kid::name,kid.name);
34     Kid::sex=newchar[strlen(kid.sex)];
35     strcpy(Kid::sex,kid.sex);
36 }
37 
38 Kid::~Kid()
39 {
40     cout<<"dispose object kid"<<endl;
41     delete []name;
42     delete []sex;
43 }
44 
45 void Kid::showKid()
46 {
47     cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
48 }
49 
50 int main()
51 {
52     Kid kid(10,"rookie_j","");
53     kid.showKid();
54 
55     Kid kid2(kid);
56     kid2.showKid();
57 
58     Kid kid3=kid2;
59     kid3.showKid();
60 
61 return0;
62 }

结果:

  同样的默认的拷贝构造函数:复制出与源对象的数据成员的值一样的新对象。调用拷贝构造函数的3种情况:(1)Kid kid2(kid1)或Kid kid2=kid1;(2)函数的形参是类的对象:fun(Kid kid){kid.showKid();}; int main(){Kid kid(10,"Rookie_j","男");fun(kid);return 0;};(3)函数返回值为类的对象:Kid fun(){Kid kid(10,"Rookie_j","男"); return kid;} int main(){ Kid kid; kid=fun();kid.showKid();return 0;};

  3.最后还是一样用一个实例来总结一下今天所说的内容(开发工具:vs2010):

View Code
  1 #include "stdafx.h"
  2 #include <iostream>
  3 
  4 usingnamespace std;
  5 
  6 class Kid
  7 {
  8 private:
  9 int age;
 10 char*name;
 11 char*sex;
 12 public:
 13         Kid(int age,char*name,char*sex);
 14         Kid(const Kid &kid);  //自定义拷贝函数
 15 ~Kid(); 
 16 void showKid();
 17 };
 18 
 19 
 20 Kid::Kid(int age,char*name,char*sex)
 21 {
 22     Kid::age=age;
 23     Kid::name=newchar[strlen(name)];
 24     strcpy(Kid::name,name);
 25     Kid::sex=newchar[strlen(sex)];
 26     strcpy(Kid::sex,sex);
 27 }
 28 
 29 //Kid::Kid(int age,char *name,char *sex):age(age),name(name),sex(sex) //用成员初始化表对数据成员初始化
 30 //{
 31 //
 32 //}
 33 
 34 Kid::Kid(const Kid &kid)
 35 {
 36     Kid::age=kid.age*2;
 37     Kid::name=newchar[strlen(kid.name)];
 38     strcpy(Kid::name,kid.name);
 39     Kid::sex=newchar[strlen(kid.sex)];
 40     strcpy(Kid::sex,kid.sex);
 41 }
 42 
 43 Kid::~Kid() //自定义析构函数
 44 {
 45     cout<<"dispose object kid"<<endl;
 46     delete []name; //delete运算符释放存储空间
 47     delete []sex;
 48 }
 49 
 50 void Kid::showKid()
 51 {
 52     cout<<"孩子:"<<endl<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
 53 }
 54 
 55 class Car
 56 {    
 57 public:
 58 char*no;
 59 char*brand;
 60 int speed;
 61 void showCar();
 62 ~Car(){};//仿默认析构
 63 };
 64 
 65 
 66 
 67 void Car::showCar()
 68 {
 69     cout<<"汽车:"<<endl<<"号码:"<<no<<endl<<"品牌:"<<brand<<endl<<"速度:"<<speed<<"km/h"<<endl;
 70 }
 71 
 72 int main()
 73 {
 74     Kid kid(10,"rookie_j","");
 75     kid.showKid();
 76 
 77     cout<<"--------------------"<<endl;
 78 
 79     Kid kid2(kid); //代入法调用拷贝构造函数
 80     kid2.showKid();
 81 
 82     cout<<"--------------------"<<endl;
 83 
 84     Kid kid3=kid2; //赋值法调用拷贝构造函数
 85     kid3.showKid();
 86 
 87     cout<<"--------------------"<<endl;
 88 
 89     Kid *ptr=new Kid(10,"rookie_x",""); //使用new运算符动态创建对象
 90     ptr->showKid();
 91 
 92     cout<<"--------------------"<<endl;
 93 
 94 //delete ptr; //释放对象所占的存储空间
 95 
 96     Car car={"8888888","Benz",200},car2;//只有没定义构造函数的类,才能用初始值表初始化公有数据成员,默认构造
 97     car.showCar();
 98     
 99 
100     cout<<"--------------------"<<endl;
101 
102     car2=car;//默认拷贝构造函数或car2(car)
103     car2.showCar();
104 
105     cout<<"--------------------"<<endl;
106 
107 return0;
108 }

结果:

但在运行的时候,发现一个问题如果把delete ptr; 这句的注释去掉,结果汽车的情况就显示不出来了;

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值