1、三种继承关系
- 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问
- 私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。(最常见)
- 保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的
派生类成员函数或友元访问
,基类的私有成员仍然是私有的。(子类对象不可能直接访问到基类的成员)
class Derived : protected Base
{
public:
int getx(void){return _x;} //_x是基类的成员数据(公有的/保护的)
};
int main(int argc,char **argv)
{
Base apple;
Derived banana;
cout << banana.Base::x << endl; // 错误的,
cout<< banana.getx()<<endl; //正确的,派生类成员函数
}
2.类继承关系中构造函数、析构函数执行次序
- 先是构造基类,再构造子类
- 显示析构子类,再析构基类
#include <iostream>
using namespace std;
class Base // 基类、父类
{
public:
Base(){cout << "B" << endl;}
~Base(){cout << "~B" << endl;}
};
// 派生类、子类
class Derived : public Base // is-a关系
{
public:
Derived() {cout << "D" << endl;}
~Derived(){cout << "~D" << endl;}
};
int main(void)
{
Derived d; // 先构造Base,再构造Derived;
// 先析构Derived,再析构Base
}
执行结果:
gec@ubuntu:~$ ./main
B
D
~D
~B
3,多重继承、多重is-a关系
- 多重继承要注意二义性
- 父类的作用域比子类的作用域大,因此在子类和父类定义一个相同的变量时,子类的变量会掩盖父类的变量,父类的变量还在
- 当子类继承两个父类,而且两个父类有相同的变量时,这时我们就不可以直接通过父类来调用该变量,而是应该调用基类作用域中的变量
#include <iostream>
using namespace std;
class A
{
public:
void funA(){cout<< "class A" << endl;}
int x;
int y=10;
};
class B
{
public:
void funB(){cout<< "class B" << endl;}
int x;
};
// 同时继承两个父类
class C : public A, public B
{
};
int main()
{
C c;
c.funA();
c.funB();
c.y = 100; //正确
c.x =100; //错误的
c.A::x = 100;
return 0;
}
4.虚继承、菱形继承
- 如果都是实继承,那么A类中的x变量,在D类中就有两个xx,而且是相同的。但是这样是不符合我们想要的(但却是合法的)。
- 因此B,和C类要虚继承于A
- 让D类直接来调用A类
虚继承:
#include <iostream>
using namespace std;
// 交通工具
class A
{
public:
A(int id):ID(id){cout << "构造A" << endl;}
int ID;
};
class B : virtual public A
{
public:
// 以下语句中的A(id)是显式地调用A的构造函数
// 当直接定义B对象的时候,显然会调用它
// 但是如果是通过D触发,那么就不会调用
B(int id):A(id){cout << "构造B" << endl;}
};
class C : virtual public A
{
public:
C(int id):A(id){cout << "构造C" << endl;}
};
class D : public B, public C
{
//初始化列表不但要初始化B和C,还要初始化A类
public:
D(int id):A(id),B(id),C(id){cout << "构造D" << endl;}
};
int main()
{
D d(99);
cout << d.ID << endl;
return 0;
}
执行结果:
构造A
构造B
构造C
构造D
99
实继承:
#include <iostream>
using namespace std;
// 交通工具
class A
{
public:
A(int id=0):ID(id){cout << "构造A" << endl;}
int ID;
};
class B : public A
{
public:
// 以下语句中的A(id)是显式地调用A的构造函数
// 当直接定义B对象的时候,显然会调用它
// 但是如果是通过D触发,那么就不会调用
B(int id=0):A(id){cout << "构造B" << endl;}
};
class C : public A
{
public:
C(int id=0):A(id){cout << "构造C" << endl;}
};
class D : public B, public C
{
//初始化B,C类即可
public:
D(int id):B(id),C(id){cout << "构造D" << endl;}
};
int main()
{
D d(99);
cout << d.B::ID << endl;
return 0;
}
执行结果:
构造A
构造B
构造A
构造C
构造D
99
构造了两次A,不是我们想要的