继承
减少重复的代码,提高代码复用性。
- 语法:
class 子类 : 继承方式 父类 - News 子类 派生类
- BasePage 父类 基类
继承方式
公共继承
- 父类中公共权限,子类中变为公共权限
- 父类中保护权限,子类中变为保护权限
- 父类中私有权限,子类访问不到
保护继承
- 父类中公共权限,子类中变为保护权限
- 父类中保护权限,子类中变为保护权限
- 父类中私有权限,子类访问不到
私有继承
- 父类中公共权限,子类中变为私有权限
- 父类中保护权限,子类中变为私有权限
- 父类中私有权限,子类访问不到
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Base1
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son1 :public Base1
{
public:
void func()
{
m_A = 100;
m_B = 100;
}
};
void test01()
{
Son1 s1;
s1.m_A = 100;
}
class Base2
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son2 : protected Base2
{
public:
void func()
{
m_A = 100;
m_B = 100;
}
};
void test01()
{
Son2 s;
}
class Base3
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son3 :private Base3
{
public:
void func()
{
m_A = 100;
m_B = 100;
}
};
class GrandSon3 :public Son3
{
public:
void func()
{
}
};
void test03()
{
Son3 s;
}
int main(){
system("pause");
return EXIT_SUCCESS;
}
总结
protected、private 方式的继承会增加父类中被子类继承下的成员方法及成员属性的访问级别,调整到对应的继承级别。public 方式保持父类的级别进行继承。
继承中的对象模型
- 父类中的私有属性,子类是继承下去了,只不过由编译器给隐藏了,访问不到
- 可以利用开发人员工具查看对象模型
- 打开开发人员命令工具并跳转到所要查看的文件对应的盘符
- 跳转文件路径 cd到文件路径下
cl /d1 reportSingleClassLayout类名 文件名
#define _CRT_SECURE_NO_WARNINGS
#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;
};
void test01()
{
cout << "size of Son = " << sizeof(Son) << endl;
}
int main() {
test01();
system("pause");
return EXIT_SUCCESS;
}
继承中的构造和析构
- 先调用父类默认构造,再调用其他成员构造, 再调用自身构造 ,析构的顺序与构造相反
class Base1
{
public:
Base1()
{
cout << "Base1的构造函数调用" << endl;
}
~Base1()
{
cout << "Base1的析构函数调用" << endl;
}
};
class Other
{
public:
Other()
{
cout << "Other的构造函数调用" << endl;
}
~Other()
{
cout << "Other的析构函数调用" << endl;
}
};
class Son1 :public Base1
{
public:
Son1()
{
cout << "Son1的构造函数调用" << endl;
}
~Son1()
{
cout << "Son1的析构函数调用" << endl;
}
Other other;
};
void test()
{
Son1 s;
}
- 若父类中没有默认构造,子类继承后,可以利用初始化列表语法 ,显示调用父类中的其他构造函数
class Base2
{
public:
Base2(int a)
{
this->m_A = a;
cout << "Base2的构造函数调用" << endl;
}
int m_A;
};
class Son2 :public Base2
{
public:
Son2(int a = 1000 ) :Base2(a)
{
cout << "Son2的构造函数调用" << endl;
}
};
void test02()
{
Son2 s;
cout << s.m_A << endl;
}
- 父类中 构造、析构、拷贝构造 、operator= 是不会被子类继承下去的
继承中的同名成员处理
- 我们可以利用作用域 访问父类中的同名成员
class Base
{
public:
Base()
{
this->m_A = 10;
}
void func()
{
cout << "Base中的func调用" << endl;
}
void func(int a)
{
cout << "Base中的func(int)调用" << endl;
}
int m_A;
};
class Son :public Base
{
public:
Son()
{
this->m_A = 20;
}
void func()
{
cout << "Son中的func调用" << endl;
}
int m_A;
};
void test()
{
Son s1;
cout << "s1.m_A = " << s1.m_A << endl;
cout << "Base中的m_A = " << s1.Base::m_A << endl;
}
- 当子类重新定义了父类中的同名成员函数,子类的成员函数会隐藏掉父类中所有重载版本的同名成员,可以利用作用域显示指定调用
class Base
{
public:
Base()
{
this->m_A = 10;
}
void func()
{
cout << "Base中的func调用" << endl;
}
void func(int a)
{
cout << "Base中的func(int)调用" << endl;
}
int m_A;
};
class Son :public Base
{
public:
Son()
{
this->m_A = 20;
}
void func()
{
cout << "Son中的func调用" << endl;
}
int m_A;
};
void test()
{
Son s1;
s1.func();
s1.Base::func(10);
}
继承中的同名静态成员处理
结论和 非静态成员 一致,只不过调用方式有两种
- 通过对象
- 通过类名,通过类名
Son:: 的方式 访问父类作用域Base:: 下的m_A静态成员变量(Son::Base::m_A )
class Base
{
public:
static void func()
{
cout << "Base中的func调用 " << endl;
}
static void func(int a)
{
cout << "Base中的func(int a)调用 " << endl;
}
static int m_A;
};
int Base::m_A = 10;
class Son :public Base
{
public:
static void func()
{
cout << "Son中的func调用 " << endl;
}
static int m_A;
};
int Son::m_A = 20;
void test01()
{
Son s;
cout << "m_A = " << s.m_A << endl;
cout << "Base中的m_A = " << s.Base::m_A << endl;
cout << "m_A = " << Son::m_A << endl;
cout << "Base中的m_A = " << Base::m_A << endl;
cout << "Base中的m_A = " << Son::Base::m_A << endl;
}
void test02()
{
Son s;
s.func();
s.Base::func();
Son::func();
Base::func(1);
Son::Base::func(1);
}
多继承基本语法
class 子类名 : 继承方式 父类1 , 继承方式 父类2 - 当多继承的两个父类中有同名成员,需要加作用域区分
class Base1
{
public:
Base1()
{
this->m_A = 10;
}
int m_A;
};
class Base2
{
public:
Base2()
{
this->m_A = 20;
}
int m_A;
};
class Son : public Base1, public Base2
{
public:
int m_C;
int m_D;
};
void test01()
{
cout << "sizeof Son = " << sizeof(Son) << endl;
Son s;
cout << s.Base1::m_A << endl;
cout << s.Base2::m_A << endl;
}
菱形继承
两个类有公共的父类 和共同的子类 ,发生菱形继承
-
菱形继承导致数据有两份,浪费资源 -
解决方案:利用虚继承可以解决菱形继承问题
class Animal
{
public:
int m_Age;
};
class Sheep : virtual public Animal{};
class Tuo : virtual public Animal{};
class SheepTuo : public Sheep, public Tuo
{
};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 20;
cout << "Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "Tuo::m_Age = " << st.Tuo::m_Age << endl;
cout << "age = " << st.m_Age << endl;
}
void test02()
{
SheepTuo st;
st.m_Age = 10;
int offset = *(((int*)(*(int*)&st)) + 1);
cout << offset << endl;
cout << *((int*)*((int*)&st + 1) + 1) << endl;
cout << "m_Age = " << ((Animal*)((char*)&st + offset))->m_Age << endl;
cout << "m_Age = " << *((int*)((char*)&st + offset)) << endl;
}
class Sheep : virtual public Animal{}; - 当发生虚继承后,
sheep 和tuo 类中 继承了一个 vbptr 指针 虚基类(base class Sheep , base class Tuo )指针 指向的是一个 虚基类表 vbtable - 虚基类表中记录了 偏移量 ,通过偏移量 可以找到唯一的一个
m_Age - 利用地址偏移找到
vbtable 中的偏移量 并且访问数据 ((char*)&st + offset) 移动到virtual base Animal ((Animal*)((char*)&st + offset))->m_Age 取出m_Age 的值
cout << "m_Age = " << *((int*)((char*)&st + offset)) << endl; 直接展开Animal ,获取int 类型的m_Age 值
|