CPP学习之——向基类构造函数传递参数(12.13)

一 应用场景

从基类派生一个子类可以为我们节省许多时间和工序,比如说假如我们为一个客户定做一个简易的售票系统,该系统被全面测试过,没有出现问题,客户也很满意,于是我们便将系统编译成可执行文件交付客户使用,但是随着时间的推移,客户又有了新的要求,他想要在这个售票系统中假如刷卡功能,但是在C++中,我们可以用继承来解决,我们只需要再派生一个基于售票系统的子类,在里面添加一个刷卡的功能就可以了,而基类的数据则完全不用改变

二 原因分析

继承固然为我们节省了不少时间和工序,但是由于子类是从基类派生出去的,因此我们在创建派生类的对象时,仍然需要对基类进行初始化。这个原因其实也不难理解,因为子类将基类的所有成员都继承了过去,所以被继承的成员也就会出现在子类里,那么我们在构造一个子类的对象时,难免就会调用基类的构造函数。

三 初始化方法

在创建派生类的构造函数时,有两种方法对数据进行初始化.

  • 第一种:在派生类中创建一个构造函数,然后初始化所有数据(从基类那里继承来的数据和子类的数据)。这种方法显然是多余的,因为基类已经有了恰当的构造函数,为何还要重复构造呢。况且在派生类中对基类进行初始化的这种做法也是不可取的。
  • 第二种:在派生类中创建一个构造函数,用该构造函数调用基类的构造函数并且向构造函数传递初始值。显然,第二种做法效率要高一些,并且出错的几率要小些

四 使用第一种方式演示及结果输出

4.1 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
#include<string>
using namespace std;
class father
{
protected:
string name;
int tall;
public:
father(string a, int i);
father() {cout << "构造基类" << endl;}
~father() {cout << "释放基类对象" << endl;}
void print() {cout << "name:" << name << "身高为:" << tall << endl;}
};
father::father(string a, int i)
{
cout << "在基类的构造函数内" << endl;
name = a;
tall = i;
print();
cout << "离开基类的构造函数" << endl;
}
class son: public father
{
private:
int weight;
public:
son(string a, int i, int j);
void print1();
~son() {cout << "释放子类对象" << endl;}
};
son::son(string a, int i, int j)
{
name = a;
tall = i;
weight = j;
cout << "在子类的构造函数内" << endl;
}
void son::print1()
{
father::print();
cout << "体重:" << weight << endl;
}
int main()
{
son Mike("Mike",180,80);
Mike.print1();
cout<<"程序执行结束"<<endl;
return 0;
}

4.2 输出结果

1
2
3
4
5
6
7
构造基类
在子类的构造函数内
name:Mike身高为:180
体重:80
程序执行结束
释放子类对象
释放基类对象

五 使用第二种方式演示及结果输出

5.1 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#include<string>
using namespace std;
class father
{
protected:
string name;
int tall;
public:
father(string a, int i);
father() {cout << "构造基类" << endl;}
~father() {cout << "释放基类对象" << endl;}
void print() {cout << "name:" << name << "身高为:" << tall << endl;}
};
father::father(string a, int i)
{
cout << "在基类的构造函数内" << endl;
name = a;
tall = i;
print();
cout << "离开基类的构造函数" << endl;
}
class son: public father
{
private:
int weight;
public:
son(string a, int i, int j);
void print1();
~son() {cout << "释放子类对象" << endl;}
};
son::son(string a, int i, int j):father(a,i)
{
weight = j;
cout << "在子类的构造函数内" << endl;
}
void son::print1()
{
father::print();
cout << "体重:" << weight << endl;
}
int main()
{
son Mike("Mike",180,80);
Mike.print1();
cout<<"程序执行结束"<<endl;
return 0;
}

5.2 输出结果

1
2
3
4
5
6
7
8
9
在基类的构造函数内
name:Mike身高为:180
离开基类的构造函数
在子类的构造函数内
name:Mike身高为:180
体重:80
程序执行结束
释放子类对象
释放基类对象

六 总结

另外我们在使用第二种方式的时候要注意:

  • 如果没有定义派生类的构造函数,那么将默认执行基类的构造函数
  • 如果派生类要向基类传递参数,那么必须在派生类里定义一个构造函数,该函数只起向基类传递参数的作用
  • 如果只需要调用基类的构造函数,不用向基类传递参数的话,那么派生类不用定义构造函数