构造函数 ,是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。(摘自百度百科构造函数)。
?
一、最基本的构造函数
?
复制代码
1 class Base
2 {
3 public:
4 ? ? Base(int var) : m_Var(var)
5 ? ? {
6 ? ? }
7 private:
8 ? ? int m_Var;
9 };
复制代码
?以上构造函数的执行过程:
?
1)传参 ? 2)给类数据成员开辟空间 ? ? 3)执行冒号语法给数据成员初始化 ? ?4)执行构造函数括号里面的内容
?
这里需要说明的是:冒号语法后面的内容相当于int a = 10;(初始化),而构造函数括号里面则是相当于是int a; a = 10;(赋初值)
?
二、拷贝构造函数
?
复制代码
?1 class Base
?2 {
?3 public:
?4 ? ? Base(int var) : m_Var(var)
?5 ? ? {
?6 ? ? }
?7 ? ? //拷贝构造函数
?8 ? ? Base(Base &ref) : m_Var(ref.m_Var)
?9 ? ? {
10 ? ? }
11 private:
12 ? ? int m_Var;
13 };
复制代码
为什么拷贝构造函数的参数只能用引用呢?
?
这就要从拷贝构造函数式数码时候触发开始说起了,以下几种情况都会自动调用拷贝构造函数:
?
1)用一个已有的对象初始化一个新对象的时候
?
2)将一个对象以值传递的方式传给形参的时候
?
3)函数返回一个对象的时候
?
所以当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。(摘自百度百科拷贝构造函数)。
?
?
?
拷贝构造函数,一般不需要自己编写,系统默认的拷贝构造函数就能抗住了,但是有些情况需要在构造的时候开辟空间,这时候就需要拷贝构造函数了,如下代码是摘自林锐博士的高质量
C++
编程指南一文。
?
复制代码
?1 class String
?2 {
?3 public:
?4 ? ? String(const char *str = NULL); // 普通构造函数
?5 ? ? String(const String &other); ? ?// 拷贝构造函数
?6 ? ? ~ String(void); ? ? ? ? ? ? ? ? // 析构函数
?7 private:
?8 ? ? char *m_data; // 用于保存字符串
?9 };
10 // String 的析构函数
11 String::~String(void)?
12 {
13 ? ? delete [] m_data;
14 ? ? // 由于m_data 是内部数据类型,也可以写成 delete m_data;
15 }
16?
17 // String 的普通构造函数
18 String::String(const char *str)?
19 {
20 ? ? if(str==NULL)
21 ? ? {
22 ? ? ? ? m_data = new char[1]; // 若能加 NULL 判断则更好
23 ? ? ? ? *m_data = '\0';
24 ? ? }
25 ? ? else
26 ? ? {
27 ? ? ? ? int length = strlen(str);
28 ? ? ? ? m_data = new char[length+1]; // 若能加 NULL 判断则更好
29 ? ? ? ? strcpy(m_data, str);
30 ? ? }
31 }
32 // 拷贝构造函数
33 String::String(const String &other)?
34 {
35 ? ? int length = strlen(other.m_data);
36 ? ? m_data = new char[length+1]; // 若能加 NULL 判断则更好
37 ? ? strcpy(m_data, other.m_data);
38 }
复制代码
?三、普通派生类构造函数的写法
?
定义派生类对象的时候,会按如下步骤执行构造操作:
?
1)传参 ? ? 2)根据继承时的声明顺序构造基类 ? ?3)给类数据成员开辟空间 ? ?4)执行冒号语法后面的语句 ? ?5)执行构造函数函数体语句
?
复制代码
?1 class Base
?2 {
?3 public:
?4 ? ? Base(int b) : m_b(b)
?5 ? ? {
?6 ? ? }
?7 private:
?8 ? ? int m_b;
?9 };
10?
11 class Derived : public Base
12 {
13 public:
14 ? ? //普通派生类构造函数的写法
15 ? ? Derived(int b, int d) : Base(b), m_d(d)
16 ? ? {
17 ? ? }
18 private:
19 ? ? int m_d;
20 };
复制代码
再写一个多继承的示例:
?
复制代码
?1 class Base1
?2 {
?3 public:
?4 ? ? Base1(int b1) : m_b1(b1)
?5 ? ? {
?6 ? ? }
?7 private:
?8 ? ? int m_b1;
?9 };
10?
11 class Base2
12 {
13 public:
14 ? ? Base2(int b2) : m_b2(b2)
15 ? ? {
16 ? ? }
17 private:
18 ? ? int m_b2;
19 };
20?
21 class Derived : public Base1, public Base2
22 {
23 public:
24 ? ? Derived(int b1, int b2, int d) : Base1(b1), Base2(b2), m_d(d)
25 ? ? { //注意冒号语法后面的顺序无所谓,创造基类是按照上面的继承声明顺序来进行的...
26 ? ? }
27 private:
28 ? ? int m_d;
29 };
复制代码
四、含有虚继承的派生类构造函数的写法
?
为何要用到虚继承?
?
虚继承主要是针对多继承时,出现二义性问题而提出的。比如,如下代码就需要用到虚继承,否则的话Derived类继承时,Base类就会不明确。
?
虚继承构造函数的执行按照如下步骤:
?
1)传参 2)创建基类,注意这时候需要显示创建所有“有参构造函数”的基类,包括直接基类,间接基类。 3)给类数据成员开辟空间 ?4)执行冒号语法 ?5