c++ 继承与派生(二)
先让我们回顾一下上次的要点:
- 继承与派生的概念
- 派生类的构造函数和析构函数的执行顺序与规则
- 多继承的声明与实现
- 基类成员访问原则
- 赋值兼容性
- 虚基类的概念
派生类的构造函数与析构函数
在继承机制中,基类的构造函数和析构函数是不能继承的,也就是说,基类的构造函数不能作为派生类的构造函数,派生类的构造函数负责对来自基类数据成员和新增加的数据成员进行初始化。
构造函数的调用顺序如下:
(1)基类的构造函数
(2)对象成员的构造函数有多个时按声明的顺序
(3)派生类的构造函数
派生类的构造实例:
class B {
public:
B() {
cout << "ConstructingB..." << endl;
}
};
class C {
public:
C(){
cout << "ConstructingC..." << endl;
}
};
class D :public B
{
private:
C c1;
public:
D() {
cout << "ConstructingD..." << endl;
}
};
int main()
{
D d1;
return 0;
}
运行结果为
Constructing B…
Constructing C…
Constructing D…
析构函数与构造函数执行顺序相反
派生类构造函数和析构函数的构造规则:
(1)如基类中定义了默认的构造函数,且该默认构造函数能够完成派生类对象中基本成员的构造,则派生类构造函数无需显示调用基类构造函数,直接调用基类的默认构造函数即可。
例:
class Base {
public:
Base() {
a = 0; }
Base(int i) {
a = i; }
protected:
int a;
};
class Derived :public Base {
//隐式地调用基类地构造函数
public:
Derived() {
b = 0; }
Derived(int i) {
b = i; }
void Print()
{
cout << "a =" << a << ",b=" << b << endl;
}
private:
int b;
};
int main()
{
Derived d1;
Derived d2(12);
d1.Print();
d2.Print();
return 0;
}
运行结果:
a =0,b=0
a =0,b=12
(2)若基类中定义了有参数地构造函数,或者所定义的默认构造函数不能完成基类成员的构造,则需要用到“成员初始化列表”。
因此派生类构造函数定义的一般格式如下:
派生类名(参数类表):基类参数构造(参数列表1),子对象成员(参数列表)…
{
派生类构造函数体
}
示例:
class Date {
private:
int year, month, day;
public:
Date(int y = 2000, int m = 6, int d = 10)
{
year = y;
month = m;
day = d;
}
void Print()
{
cout << year << "-" << month << "-" << day << endl;
}
};
class Student {
protected:
int number;
string name;
char gender;
public:
Student()
{
number = 0;
name = "NO NAME";
gender = 'M';
}
Student(int n, string s, char x)
{
number = n;
name = s;
gender = x;
}
};
class Undergraduate :public Student {
public:
Undergraduate(int n, string s, char x, int a, int y, int m, int d) :
Student(n, s, x), birth(y, m, d)
{
age = a;
}
Undergraduate()
{
age = 0;
}
void Print()
{
cout << "number:" << number << endl;
cout << "name:" << name << endl;
cout << "gender:" << gender << endl;
cout << "age:" << age << endl;
cout << "birthday:";
birth.Print();
}
private:
int age;
Date birth;
};
int main()
{
Undergraduate st1;
Undergraduate st2(1001, "Zhao", 'F', 20, 2009, 6, 11);
st1.Print();
st2.Print();
return 0;
}
运行结果:
number:0
name:NO NAME
gender:M
age:0
birthday:2000-6-10
number:1001
name:Zhao
gender:F
age:20
birthday:2009-6-11
多继承
多继承下派生类的声明格式如下:
class 派生类名:继承方式1基类名1,继承方式2基类名2,…
{
派生类类体;
}
派生类构造函数执行顺序时先执行所有基类的构造函数,再执行派生类本身的构造函数,处于同一层次的各基类构造函数取决于声明派生类时所指定各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。相对应的是,析构函数的调用顺序与构造函数完全相反。
基类成员访问和赋值兼容性
若多个基类中定义有同名成员,则派生类对这些同名成员的访问可能存在冲突。为避免可能出现的成员访问冲突,需要用成员名限定的方法显式地指定要访问的成员。
#include<iostream>
using namespace std;
class MP3player {
public:
void Play()
{
cout << "Play mp3 music" << endl;
}
};
class Videoplayer {
public:
void Play()
{
cout << "Play vider" << endl;
}
};
class MP4player :public MP3player, public Videoplayer {
public:
/**/
};
int main()
{
MP4player Mp4;
Mp4.MP3player::Play();
Mp4.Videoplayer::Play();
return 0;
}
为解决上述成员访问冲突问题,在main()函数中,采用了成员名限定的方法对具体基类的同名成员进行访问,格式如下:
基类名::成员函数
即在成员名Play()前显示指定该成员所属基类,这样有效的避免了对该成员访问的二义性错误,同样对于基类的数据成员,该原则同样适用。
当派生类中定义了与基类中同名的成员时,则从基类中继承得到的成员被派生类的同名成员覆盖,派生类对基类成员的直接访问将被派生类中该成员取代,为访问基类成员,必须采用成员名限定方法
还没有评论,来说两句吧...