C++的三大特性:继承、多态、封装
这篇博客讨论下继承和多态
继承
继承的本质是代码复用。
继承了什么:
除构造函数和析构函数以外的所有成员
继承了作用域
继承写法:
类标识 类名:继承方式 基类名
继承和派生的关系:
派生类的内存布局:
派生类对象的构造和析构:
构造:
1、系统调用基类的构造
2、系统调用派生类的构造
析构:
1、系统调用派生类的析构
2、系统调用基类的析构
基类中不同访问限定符下的成员以不同继承方式继承后在派生类中的访问限定
public:任意位置访问
private:本类类中访问
protected:本类、子类类中访问
类和类的关系:
组合:a part of has_a
继承:a kind of is_a
代理:迭代器
同名函数的关系:
重载:(重定义) 三要素: 同名 不同参数 同作用域
隐藏:派生类中隐藏了基类中所有的同名函数 1、同名 2、不同作用域
#include<iostream>
class Base
{
public:
Base(int b):mb(b)
{}
void Show()
{
std::cout<<"Base::"<<mb<<std::endl;
}
private:
int mb;
};
class Derive:public Base
{
public:
Derive(int d):md(d),Base(d){}
void Show()
{
std::cout<<"Derive::"<<md<<std::endl;
}
private:
int md;
};
int main()
{
Base *p = new Derive(10);
p->Show();
return 0;
}
调用了基类的Show函数,子类将父类的Show函数隐藏了,静态调用
覆盖:(重写)派生类中的虚函数覆盖基类中同名同参的虚函数(发生在续表合并过程中)
1、同名同参2、不同作用域3、都为虚函数
#include<iostream>
class Base
{
public:
Base(int b):mb(b)
{}
virtual void Show()
{
std::cout<<"Base::"<<mb<<std::endl;
}
private:
int mb;
};
class Derive:public Base
{
public:
Derive(int d):md(d),Base(d){}
void Show()
{
std::cout<<"Derive::"<<md<<std::endl;
}
private:
int md;
};
int main()
{
Base *p = new Derive(10);
p->Show();
return 0;
}
调用了子类的Show函数,子类将基类的Show函数覆盖了,动态调用
基类和派生类指向或引用的相互指向或引用:
允许基类指针或引用 指向或引用派生类对象,反之,不允许
多态
多态:同一接口不同形态
多态的本质:接口复用
静多态:编译期间 函数重载 模板
动多态:运行期间
宏多态:预编译
静态绑定又称早绑定
动态绑定又称晚绑定
class Base
{
public:
Base(int a) :ma(a)
{
//this->Show();
std::cout << "Base::Base()" << std::endl;
}
virtual void Show()
{
std::cout << "Base::ma:" << ma << std::endl;
}
void Show1()
{
Show();
}
virtual ~Base()
{
//Show();
//Show1();
std::cout << "Base::~Base()" << std::endl;
}
protected:
int ma;
};
class Derived :public Base
{
public:
Derived(int b) :mb(b), Base(b)
{
std::cout << "Derived::Derived()" << std::endl;
}
void Show()
{
std::cout << "Derived::mb:" << mb << std::endl;
}
~Derived()
{
std::cout << "Derived::~Derived()" << std::endl;
}
private:
int mb;
};
int main()
{
Base* pb1 = new Base(10);
pb1->Show();//动多态
Base* pb2 = new Derived(10);
pb2->Show();//动多态
Derived* pd1 = new Derived(10);
pd1->Show();//动多态
Base b(10);
Derived d(20);
Base& rb1 = b;
Base& rb2 = d;
rb1.Show();//动多态
rb2.Show();//动多态
Derived& rd1 = d;
rd1.Show();//动多态
b.Show();//静多态
d.Show();//静多态
return 0;
}
动多态的发生条件:
指针或引用调用虚函数 对象完整
当类中方法被virtual关键字修饰时,系统会生成一个虚函数指针(vfptr),为虚函数指针维护一个虚函数表(vftable):
虚表的写入时机:构造函数的第一行代码执行之前
基类的指针指向派生类对象 指向的是派生类对象中基类的起始位置
判断函数是否能成为虚函数:是否满足:1、能取地址 2、依赖对象调用
析构函数