目录
一、基本语法
二、继承方式
三、对象模型
四、继承中的构造与析构的顺序
五、继承中同名成员处理
六、多继承语法
七、菱形继承
一、基本语法
好处:减少重复的代码
语法: class 子类 : 继承方式 父类
子类 也称为 派生类
父类 也称为 基类
派生类中的成员,包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员
从基类继承过来的表现其共性,而新增的成员体现了其个性
二、继承方式
- class 子类 :public 父类
父类中的public、protected继承在子类中依然不变,私有权限无法继承。
- class 子类 :protected 父类
父类中的public、protected继承在子类时变为protected,私有权限无法继承。
- class 子类 :private 父类
父类中的public、protected继承在子类时变为private,私有权限无法继承。
代码示例
#include<iostream>
using namespace std;class base1{public:int m_A;
protected:int m_B;
private:int m_C;
};// public 继承
class Son1 : public base1{ void fun(){m_A = 10;m_B = 10;
// m_C = 10; //私有权限无法继承}
};
void test1(){Son1 son1;son1.m_A = 2;
// son1.m_B = 3;
// son1.m_C = 4;
}// protected 继承
class Son2 : protected base1{void fun(){m_A = 10; //变为protectedm_B = 10;//变为protected//m_C = 10; //私有权限无法继承}
};
void test2(){Son2 son2;// son2.m_A = 2; //变为protected,类外无法访问// son2.m_B = 3; //变为protected,类外无法访问// son2.m_C = 4;
}// private 继承
class Son3 : private base1{void fun(){m_A = 10; //变为privatem_B = 10; //变为private//m_C = 10; //私有权限无法继承}
};
void test3(){Son3 son3;
// son3.m_A = 2; //变为private,类外无法访问// son2.m_B = 3; //变为private,类外无法访问// son2.m_C = 4;
}
int main(){test1();test2();test3();return 0;
}
三、对象模型
父类当中的非静态成员变量都会继承下去,私有成员也会继承,只是不能访问
代码示例
#include<iostream>
using namespace std;class per{
public:int m_A;
protected:int m_B;
private:int m_C;
};class son : public per{
public:int m_D;
};void test(){cout<<"sizeof(son)="<<sizeof(son)<<endl;
}int main(){test();
}
四、继承中的构造与析构的顺序
先构造父类,再构造子类。析构顺序与构造顺序相反
代码示例
#include<iostream>
using namespace std;class Base{
public:Base(){cout<<"父类中的构造"<<endl;}~Base(){cout<<"父类中的析构"<<endl;}
};class Son : public Base{
public:Son(){cout<<"子类中的构造"<<endl;}~Son(){cout<<"子类中的析构"<<endl;}
};void test(){
// Base b;Son s;
}
int main(){test();return 0;
}
五、继承中同名成员处理
- 子类对象可以直接访问到子类中的同名函数
- 子类对象加作用域可以访问到父类中的成员函数
- 当子类与父类拥有同名的成员函数时,子类会隐藏父类中同名的成员函数,加作用域可以访问到父类中的同名函数
非静态成员变量与静态成员变量处理方式一致,只不过静态成员变量有两种访问方式:
- 通过对象进行访问 例:s.fun();
- 通过类名进行访问 例:Son::Base::fun();
代码示例
#include<iostream>
using namespace std;class Base{
public:Base(){m_A = 100;}void fun(){cout<<"Base 的 fun()"<<endl;}void fun(int ){cout<<"Base 的 fun(int)"<<endl;}int m_A;
};class Son : public Base{
public:Son(){m_A = 200;}void fun(){cout<<"Son 的 fun()"<<endl;}int m_A;};void test(){Son s;cout<<"m_A="<<s.m_A<<endl; //200cout<<"m_A="<<s.Base::m_A<<endl; //100,同名时,调用父类中的成员需要加作用域s.fun();s.Base::fun();s.Base::fun(1); // 子类与父类拥有同名的成员函数时,子类会隐藏父类中所有版本的同名函数
}
int main(){test();return 0;
}
六、多继承语法
语法:class 子类 :继承方式 父类1 , 继承方式 父类2,...
代码示例
#include<iostream>
using namespace std;class Base1{
public:Base1(){m_A = 100;}int m_A;
};class Base2{
public:Base2(){m_A = 200;}int m_A;
};class son : public Base1,public Base2{
public:son(){m_B = 200;}int m_B;
};void test (){son s;cout<<"sizeof(s)"<<sizeof(s)<<endl;cout<<s.Base1::m_A<<endl; // 继承中出现同名时需要+作用域cout<<s.Base2::m_A<<endl;
}
int main(){test();
}
七、菱形继承
关键字:virtual
如下示例:加上virtual关键字后,Sleep和Tuo 两个类里的m_Age 存的是 vbptr(虚基类指针),指向各自的 vbtable(虚基类列表)。从而直接拿到Animal 中的m_Age,解决SleepTuo 拿到两份相同数据的问题。
代码示例
#include<iostream>
using namespace std;class Animal{
public:int m_Age;
};// 当子类继承两份相同的数据时:
// 继承前加上 virtual 关键字后,变为虚继承
// 此时公共的父类 Animal 称为虚基类
class Sleep : virtual public Animal{};
class tuo : virtual public Animal{};class SleepTuo : public Sleep , public tuo{};void test1(){SleepTuo y;y.Sleep::m_Age = 100;y.tuo::m_Age = 200;cout<<y.Sleep::m_Age<<endl;cout<<y.tuo::m_Age<<endl;cout<<y.m_Age<<endl;
}int main(){test1();
}