1 继承的基本语法
class 子类:继承方式 父类
子类也称为派生类;父类也称为基类。
继承的好处:可以减少重复的代码
派生类中的成员,包含两大部分:
- 从基类继承过来的
- 自己增加的成员
从基类继承过来的表现其共性,而新增的成员体现了其个性
2 继承方式
继承一共有三种方式:
- 公共继承
- 保护继承
- 私有继承
3 继承中的对象模型
父类中的隐藏信息只是被编译器隐藏了,子类访问不到,但是还是会被继承的
#include<iostream>
using namespace std;
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;//父类中的私有属性只是被编译器隐藏了,不可以访问,但是还是被继承了
};
class Son:public Base
{
public:
int m_D;
};
int main()
{
cout<<"size of son= "<<sizeof(Son)<<endl;//16
return 0;
}
4 继承中构造和析构顺序
创建一个子类对象,是会有一个父类对象的创建的,那么其顺序是如何的呢?
构造顺序:
- 先构造父类
- 再构造子类
析构顺序与构造的顺序相反
5 继承同名成员处理方式
当子类和父类出现同名成员时,如何通过子类对象,访问的子类或者父类中同名的数据呢?
方法:
- 访问子类同名成员,直接访问即可
- 访问父类同名成员,需要加作用域
#include<iostream>
using namespace std;
class Base
{
public:
Base(){
m_A=100;
}
void func(){
cout<<"Base func"<<endl;
}
void func(int a){
cout<<"Base func (int a)"<<endl;
}
int m_A;
};
class Son:public Base
{
public:
Son(){
m_A=200;
}
void func(){
cout<<"Son func"<<endl;
}
int m_A;
};
//同名成员属性的处理方式
void test01(){
Son s;
cout<<s.m_A<<endl;//200
cout<<s.Base::m_A<<endl;//100
}
//同名成员函数的处理方式
void test02(){
Son S;
S.func();//直接调用,调用的是子类中的同名成员
S.Base::func();//调用父类中的同名成员函数
//S.func(100); 错误,因为子类中出现和父类同名的成员。子类的同名成员会隐藏掉父类中所有同名成员函数
S.Base::func(100);//还是得加作用域
}
int main()
{
test01();
test02();
return 0;
}
6 继承同名静态成员处理方式
同名静态成员处理方法和非静态处理一样,只不过有两种访问方式(通过对象、通过类名)
#include<iostream>
using namespace std;
class Base
{
public:
static int m_A;
static void func(){
cout<<"Base-static func()"<<endl;
}
};
int Base::m_A=100;
class Son:public Base
{
public:
static int m_A;
static void func(){
cout<<"Son-static func()"<<endl;
}
};
int Son::m_A=200;
//同名静态成员属性
void test01()
{
//1.通过对象访问
Son s;
cout<<s.m_A<<endl;
cout<<s.Base::m_A<<endl;
//2.通过类名访问
cout<<Son::m_A<<endl;
cout<<Son::Base::m_A<<endl;//第一个::代表类名访问方式,第二个::代表访问父类作用域下
}
//同名静态成员函数
void test02()
{
//1.通过对象调用
Son S;
S.func();
S.Base::func();
//2.通过类名调用
Son::func();
Son::Base::func();
}
int main()
{
test01();
test02();
return 0;
}
7 多继承语法
C++允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2...
多继承可以会引发父类中有同名成员出现,需要加作用域区分。C++实际开发中不建议采用多继承
8 菱形继承
菱形继承的概念:
- 两个派生类继承同一个基类
- 又有某个类同时继承着两个派生类
- 这种继承被称为菱形继承,又叫钻石继承
菱形继承的问题:
- 会产生二义性
- 孙子继承了爷爷两份数据,但其实我们只需要一份这样的数据就可以
我们可以利用虚继承来解决菱形继承的问题
#include<iostream>
using namespace std;
class Animal
{
public:
int m_Age;
};
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep:virtual public Animal{};
class Tuo:virtual public Animal{};
class SheepTuo:public Sheep,public Tuo{};
void test01()
{
SheepTuo st;
st.Sheep::m_Age=18;
st.Tuo::m_Age=28;
cout<<st.Sheep::m_Age<<endl;//28
cout<<st.Tuo::m_Age<<endl;//28
cout<<st.m_Age<<endl;//28
}
int main()
{
test01();
return 0;
}
其实质是这样的:
Sheep和Tuo类只是继承了基类的需基类指针(vbptr),会指向自身的虚基类表(vbtable),根据表格所记录的偏移量,指向属性,这样就只是继承了一份数据,解决了菱形继承的问题。
参考链接