class CProperty { // 类中,成员函数在类里面或者累外边实现均可
public:
void GetName(){GetObject();}
void SetId(int id) { m_id = id; }
protected: // 外边创建的对象不可访问
void GetObject() { GetId();}
private: // 外边创建的对象不可访问
void GetId(){}
private:
int m_id;
};
int main(int argc, char *argv[]) // 类外环境
{
CProperty a;
a.GetName(); // OK
// a.GetId(); // NO
// a.GetObject(); // NO
}
// 单继承
class CBase { // 函数的三种访问权限
public:
void Eat1() {
std::cout << "public: CBase Eat1" << std::endl;
}
protected:
void Eat2() {
std::cout << "public: CBase Eat2" << std::endl;
}
private:
void Eat3() {
std::cout << "public: CBase Eat3" << std::endl;
}
};
// 三种不同访问权限的继承方式
class CDerive1 : public CBase{
public:
void Invork() { // 类中成员函数调用
Eat1();
Eat2();
// Eat3(); // NO
}
};
class CDerive2 : protected CBase{
public:
void Invork() { // 类中成员函数调用
Eat1();
Eat2();
// Eat3(); // NO
}
};
class CDerive3 : private CBase{
public:
void Invork() { // 类中成员函数调用
Eat1();
Eat2();
// Eat3(); // NO
}
};
int main(int argc, char *argv[]) // 类外环境
{
CDerive1 d1;
d1.Eat1(); // OK
// d1.Eat2(); // NO
// d1.Eat3(); // NO
CDerive2 d2;
// d2.Eat1(); // NO
// d2.Eat2(); // NO
// d2.Eat3(); // NO
CDerive3 d3;
// d3.Eat1(); // NO
// d3.Eat2(); // NO
// d3.Eat3(); // NO
}
类型及方式 | 类外部 | 子类 | 本类 |
---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 |
protected | 不可访问 | 可以访问 | 可以访问 |
private | 不可访问 | 不可访问 | 可以访问 |
类型及继承 | public | protected | private |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | private | private | private |
class CBase {
public:
};
class CDerive : public CBase {
public:
};
int main(int argc, char *argv[]) // 类外环境
{
// 继承的初始化
CBase a; // 基类对象
CDerive b; // 派生类对象
// CDerive b = a; // 不能以基类初始化派生类对象
CDerive c = *((CDerive*)(&a)); // 不能直接强制转换,需要通过指针强制转换,只能访问派生类成员
CBase d = b; // 派生类隐式转换为基类,只能访问基类成员
CBase *e = new CDerive; // 基类指针指向派生类,基类指针可以访问派生类有访问权限的成员,多态体现
}
// 多继承
class CBase {
public:
void Eat1() {
std::cout << "public: CBase Eat1" << std::endl;
}
protected:
void Eat2() {
std::cout << "public: CBase Eat2" << std::endl;
}
private:
void Eat3() {
std::cout << "public: CBase Eat3" << std::endl;
}
};
class CDerive1 : public CBase { // protected 继承只有在派生类中可访问,通过派生类继承的派生类不能访问
public:
void Eat4() {
std::cout << "public: CDerive1 Eat3" << std::endl;
}
};
class CDerive2 : public CDerive1 { // 一般使用最多的继承方式是 public 继承
public:
};
class CBase2 {
public:
void Eat5() {
std::cout << "public: CDerive3 Eat3" << std::endl;
}
};
class CDerive4 : public CDerive2, public CBase2 { // 继承多个类
public:
};
int main(int argc, char *argv[]) // 类外环境
{
CDerive1 d1;
d1.Eat1();
CDerive2 d2; // 不能访问 protected 和 private 的成员
d2.Eat1();
d2.Eat4();
CDerive4 d4; // 继承是 public 控制符,所有基类的 public 成员都被继承
d4.Eat1();
d4.Eat4();
d4.Eat5();
}
// 菱形继承
class CBase {
public:
int m_id;
};
class CDerive1 : public CBase {
public:
};
class CDerive2 : public CBase {
public:
};
class CDerive3 : public CDerive1, public CDerive2 {
public:
void SetId(int id) {
// m_id = id; // 此处不成立,编译器找到了两个 m_id,不能决定用哪个
CDerive1::m_id = id; // 添加访问作用域解决冲突
CDerive2::m_id = id;
}
};
class CBase { // static
public:
static int GetId() { return m_id; }
static void SetId(int id) { m_id = id; }
static int m_size;
private:
static int m_id;
};
int CBase::m_size = 4;
int CBase::m_id = 10;
class CDerive : public CBase {
public:
};
int main(int argc, char *argv[]) // 类外环境
{
std::cout << "CBase::m_size : " << CBase::m_size << std::endl;
std::cout << "CDerive::m_size : " << CDerive::m_size << std::endl;
std::cout << "CBase::GetId() : " << CBase::GetId() << std::endl;
std::cout << "CDerive::GetId() : " << CDerive::GetId() << std::endl;
CBase::m_size = 8;
std::cout << "CBase::m_size : " << CBase::m_size << std::endl;
std::cout << "CDerive::m_size : " << CDerive::m_size << std::endl;
CDerive::m_size = 12;
std::cout << "CBase::m_size : " << CBase::m_size << std::endl;
std::cout << "CDerive::m_size : " << CDerive::m_size << std::endl;
std::cout << "CBase::m_size address : " << &CBase::m_size << std::endl;
std::cout << "CDerive::m_size address : " << &CDerive::m_size << std::endl;
CBase::SetId(20);
std::cout << "CBase::GetId() : " << CBase::GetId() << std::endl;
std::cout << "CDerive::GetId() : " << CDerive::GetId() << std::endl;
CDerive::SetId(30);
std::cout << "CBase::GetId() : " << CBase::GetId() << std::endl;
std::cout << "CDerive::GetId() : " << CDerive::GetId() << std::endl;
}
输出结果:
CBase::m_size : 4
CDerive::m_size : 4
CBase::GetId() : 10
CDerive::GetId() : 10
CBase::m_size : 8
CDerive::m_size : 8
CBase::m_size : 12
CDerive::m_size : 12
CBase::m_size address : 0x404010
CDerive::m_size address : 0x404010
CBase::GetId() : 20
CDerive::GetId() : 20
CBase::GetId() : 30
CDerive::GetId() : 30
class CBase { // virtual
public:
virtual void Print() { // 修饰函数,此时会默认生成类的虚函数表,子类可以重写此函数
std::cout << "CBase virtual Print" << std::endl;
}
virtual void PrintSize(int) {
std::cout << "CDerive virtual PrintSize" << sizeof (CBase) << std::endl;
}
};
class CDerive : public CBase {
public:
// 重写
// 1. 必须继承关系
// 2. 函数必须一模一样(返回值、函数名、形参类型)
// 3. 基类函数必须有 virtual 关键字
// 4. 重写函数的访问控制符权限不能大于被重写的函数访问权限
virtual void Print() override { // 重写基类函数 virtual & override 关键字可省略,默认存在
std::cout << "CDerive virtual Print" << std::endl;
}
// 隐藏
// 1. 必须继承关系
// 2. 必须函数名字相同
// 3. 参数不同时,不论有无virtual关键字,基类的函数将被隐藏
// 4. 参数相同,但是基类函数有无 virtual 关键字基类对应的函数被隐藏
void PrintSize() { // 隐藏了基类的同名函数
std::cout << "CDerive virtual PrintSize" << sizeof (CDerive) << std::endl;
}
};
int main(int argc, char *argv[])
{
CBase a;
a.Print();
a.PrintSize(1); // 调用派生类的同名函数
CDerive b;
b.Print();
b.PrintSize();
CBase *p = new CDerive;
p->Print();
p->PrintSize(1);
}
输出结果:
CBase virtual Print
CDerive virtual PrintSize8
CDerive virtual Print
CDerive virtual PrintSize8
CDerive virtual Print
CDerive virtual PrintSize8
class CBase {}; // 注意空类大小不为 0
class CBase1 {
public:
virtual void Print1() { // virtual
std::cout << "CBase1 virtual Print1" << std::endl;
}
virtual void Print2() { // virtual
std::cout << "CBase1 virtual Print2" << std::endl;
}
// 此类的 sizeof 计算为 4 + 8 + 4;
// m_a 虚函数指针vptr 内存对齐的扩展字节
int m_a;
};
class CBase2 : public CBase1 { // 默认添加虚函数列表
public:
virtual void Print1() { // virtual
std::cout << "CBase2 virtual Print1" << std::endl;
}
virtual void Print2() { // virtual
std::cout << "CBase2 virtual Print2" << std::endl;
}
// 此类的 sizeof 计算为 4 + 8 + 4;
// m_a 虚函数指针vptr 内存对齐的扩展字节
};
int main(int argc, char *argv[])
{
std::cout << "sizeof (CBase) : " << sizeof (CBase) << std::endl;
std::cout << "sizeof (CBase1) : " << sizeof (CBase1) << std::endl;
std::cout << "sizeof (CBase2) : " << sizeof (CBase2) << std::endl;
// 证明虚函数指针和虚函数表存在,虚函数指针在类的起始位置
CBase2 b2;
using Func = void (*)(void);
std::cout << "vtable address = " << (int*)&b2 << "\t" << "value = " << *((int*)&b2) << std::endl;
Func f1 = (Func)*((int*)*((int*)&b2) + 0);
f1();
Func f2 = (Func)*((int*)*((int*)&b2) + 2);
f2();
CBase1 b1;
using Func = void (*)(void);
std::cout << "vtable address = " << (int*)&b1 << "\t" << "value = " << *((int*)&b1) << std::endl;
Func f3 = (Func)*((int*)*((int*)&b1) + 0);
f3();
Func f4 = (Func)*((int*)*((int*)&b1) + 2);
f4();
return 0;
}
输出结果:
sizeof (CBase) : 1
sizeof (CBase1) : 16
sizeof (CBase2) : 16
vtable address = 0x65fdf0 value = 4216320
CBase2 virtual Print1
CBase2 virtual Print2
vtable address = 0x65fde0 value = 4216288
CBase1 virtual Print1
CBase1 virtual Print2
// 菱形继承,使用虚继承解决变量冲突
class CBase {
public:
int m_id;
};
class CDerive1 : virtual public CBase {
public:
};
class CDerive2 : virtual public CBase {
public:
};
class CDerive3 : public CDerive1, public CDerive2 {
public:
void SetId(int id) {
m_id = id;
}
};
输出结果:
class CBase { // 基类
public:
virtual ~CBase(){}
virtual void Print() {
std::cout << "CBase Print" << std::endl;
}
};
class CDerive1 : public CBase { // 派生类
public:
virtual void Print() {
std::cout << "CDerive1 Print" << std::endl;
}
};
class CDerive2 : public CBase { // 派生类
public:
virtual void Print() {
std::cout << "CDerive2 Print" << std::endl;
}
};
void Print(CBase &obj) { // 引用实现多态
obj.Print();
}
void Print(CBase *obj) { // 指针实现多态
obj->Print();
}
int main(int argc, char *argv[])
{
// 简单多态调用框架
// 多态必须发生在具有继承关系的类中,使用不同派生类初始化基类指针或引用,产生不同的行为
// 被基类指针或引用调用的函数必须是虚函数,且派生类重写了虚函数。
CDerive1 d1;
Print(d1); // 引用调用,派生类对象直接传参
Print(&d1); // 指针调用
CDerive2 d2;
Print(d2); // 引用调用,派生类对象直接传参
Print(&d2); // 指针调用
CBase &ref = d1;
Print(ref); // 引用调用,使用基类对象类直接传参
Print(&ref); // 指针调用
CBase *p1 = &d1;
Print(ref); // 引用调用,使用基类对象类直接传参
Print(&ref); // 指针调用
CBase &ref2 = d2;
Print(ref2); // 引用调用,使用基类对象类直接传参
Print(&ref2); // 指针调用
CBase *p2 = &d2;
Print(ref2); // 引用调用,使用基类对象类直接传参
Print(&ref2); // 指针调用
return 0;
}
输出结果:
CDerive1 Print
CDerive1 Print
CDerive2 Print
CDerive2 Print
CDerive1 Print
CDerive1 Print
CDerive1 Print
CDerive1 Print
CDerive2 Print
CDerive2 Print
CDerive2 Print
CDerive2 Print
class CBase { // 抽象类,完全由纯虚函数组成的类(无函数实现),派生类必须全部实现基类的纯虚函数
public:
virtual ~CBase(){}
virtual void Print() = 0; // 纯虚函数,没有函数实现
};
class CDerive : public CBase { // 派生类
public:
virtual void Print() override {
std::cout << "CDerive Print" << std::endl;
}
};
int main(int argc, char *argv[])
{
// CBase base; // 抽象类不能创建对象,抽象类只能作为基类来使用
CBase *p = new CDerive; // 使用多态
p->Print();
delete p;
return 0;
}
输出结果:
CDerive Print