目录
一、基本语法
好处:减少重复的代码
语法: 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; //变为protected
m_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; //变为private
m_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; //200
cout<<"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();
}