文章目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/c863ee091d67488b91b3cfe0bd7dc36a.jpeg#pic_center)
1.继承的引出
网站类
//新闻类
class News
{
public:
void header() {
cout<<"公共头部"<<endl;
}
void footer() {
cout<<"公共底部"<<endl;
}
void left() {
cout<<"左侧列表"<<endl;
}
void content() {
cout<<"新闻播放"<<endl;
}
};
//娱乐类
class YULE
{
public:
void header() {
cout<<"公共头部"<<endl;
}
void footer() {
cout<<"公共底部"<<endl;
}
void left() {
cout<<"左侧列表"<<endl;
}
void content() {
cout<<"火西肆。。。。"<<endl;
}
};
两种类重复的地方比较多,可以将重复的地方抽象到一个基类上
1.1继承的写法
//基类
class BasePage
{
public:
void header() {
cout<<"公共头部"<<endl;
}
void footer() {
cout<<"公共底部"<<endl;
}
void left() {
cout<<"左侧列表"<<endl;
}
};
//继承的写法
class News :public BasePage //News类继承于BasePage类
{
public:
void content() {
cout<<"新闻播放"<<endl;
}
}
class Game:public BasePage //Game类继承于BasePage类
{
public:
void content() {
cout<<"战地5直播。。。"<<endl;
}
}
在上面的例子中:BasePage叫做基类(父类),News/Yule/Game叫做子类(派生类)
2.继承方式
**语法:**class 子类: 继承方式 父类 (如上面例子的class News : public BasePage)
继承方式图例
无论什么继承方式,父类中的私有属性都无法被派生类访问。
3.继承中的对象模型
class A
{
public:
int a;
protected:
int b;
private:
int c;
};//A类对象大小为12
class B :public A
{
public:
int m_d;
};
void func()
{
B b;
C c;
D d;
cout << sizeof(b) << endl;
}
//输出:16
结果输出为16,说明了父类的private成员被派生类继承,但是被编译器隐藏所以无法访问
4.继承中的构造和析构顺序
class Parent
{
public:
Parent() {
cout << "构造Parent类" << endl;
}
~Parent()
{
cout << "析构Parten类" << endl;
}
int a;
protected:
int b;
private:
int c;
};
class Son :public Parent
{
public:
Son()
{
cout << "构造Son类" << endl;
}
~Son()
{
cout << "析构Son类" << endl;
}
int m_d;
};
int main()
{
Son s;
return 0;
}
子类会继承父类的成员属性和成员函数
但是子类不好继承父类的构造函数和析构函数
4.1当父类没有默认构造函数时
class Parent
{
public:
Parent(int a) {
_a = a;
}
~Parent(){}
int _a;
protected:
int b;
private:
int c;
};
class Son :public Parent
{
public:
Son(int a,int d=10):Parent(a){
m_d = d;
}
~Son(){}
void Print()
{
cout << this->_a <<" "<< this->m_d << endl;
}
int m_d;
};
int main()
{
Son s(5);
s.Print();
return 0;
}
当父类不存在默认构造函数时,需要派生类在初始化列表的位置显示调用父类的构造函数
输出5 10
5.继承中的成员处理
5.1继承中的同名成员处理
class Parent
{
public:
Parent() {
_a = 10;
}
~Parent()
{}
void func(){
cout<<this._a<<endl;
}
int _a;
};
class Son :public Parent
{
public:
Son() {
_a = 20;
}
void func(){
cout<<this._a<<endl;
}
int _a;
};
Son s;
cout << s._a << endl;
输出结果为:20
根据就近原则,先调用子类的同名成员
但是如果想要调用父类的同名成员?方式:调用作用域
cout << s.Parent::_a << endl;
//输出为10
如果子类和父类拥有同名的函数和成员,子类不会覆盖父类的成员和函数,只是加上作用域隐藏;
调用规则满足就近原则,如果想要调用父类,加上作用域调用。
5.2继承中静态成员的处理
首先类的静态成员和静态成员函数属于整个类,位于静态区。
class Parent
{
public:
int _a;
static int m_st;
};
int Parent::m_st = 50;
class Son :public Parent
{
public:
int _a;
static int m_st;
};
int Son::m_st = 60;
int main()
{
Son s;
cout <<"Parent m_st:"<<Parent::m_st<<"Son m_st"<<Son::m_st <<"Son::Parent::m_st"<<Son::Parent::m_st<< endl;
return 0;
}
输出:Parent m_st:50 Son m_st:60 Son::Parent::m_st:50
5.3非自动继承的成员函数
不是所有的函数都可以自动从基类继承到派生类中。比如基类的构造函数和析构函数;另外operator=也不能被继承,因为它完成类似构造函数的行为。
在继承的过程中,如果没有创建这些函数,编译器会自动生成它们。
6.多继承问题
我们可以同时从多个类继承。但是多继承是饱受争议的,从多个类继承可能会导致函数、变量等同名导致较多的歧义。需要加上作用域
**语法:**class 类名: 继承方式一:父类1,继承方式二,父类2…
6.1菱形继承和虚继承
两个派生类继承同一个基类,而又有某个类同时继承两个派生类,这种继承方式就被称为菱形继承
菱形继承带来的问题
这里羊继承了动物的数据和函数,驼也继承了动物类的数据和函数,羊驼调用数据和函数时就会出现二义性。
解决方案:虚继承
class animal{
public:
int m_age;
};
//虚基类
class sheep:virtual public animal{
};
//虚基类
class tuo:virtual public animal{
};
class sheeptuo:public sheep,public tuo{
};
//最后就只剩下一份数据和函数
在菱形继承内部结构中,如这里的sheeptuo类的内部结构
- 1.内容有虚基类指针
- 2.虚基类指针指向一张虚基类表
- 3.通过虚基类表可以找到偏移量
- 4.找到公共的成员
int main()
{
sheeptuo st;
cout << sizeof(st) << endl;
return 0;
}
输出的结果为:12
分别存放了sheep类的虚基类指针< vbptr >和tuo类的虚基类指针< vbptr >
非虚基类继承
class animal {
public:
int m_age;
};
class sheep : public animal {
};
class tuo : public animal {
};
class sheeptuo :public sheep, public tuo {
};
int main()
{
sheeptuo st;
cout << sizeof(st) << endl;
return 0;
}
//输出:8