C++:继承和多态

虚函数:只有类的成员函数才能定义为虚函数

虚函数 在类的成员函数前面加上一个 virtual 关键字, 此时这个成员函数就叫做虚函数
虚函数 当在子类中定义了一个与父类完全相同的虚函数的时候,此时就叫做子类的虚函数重写了父类的虚函数
构成多态的条件 派生类重写基类的虚函数实现多态, 必须要求函数名相同参数列表以及返回值相同(协变除外)
协变 派生类重写基类的虚函数的时候函数名相同, 参数列表相同, 但是返回值可以不同(返回值是父子关系)

静态成员函数不能定义为虚函数

静态成员函数是属于这个类的, 它不属于某个对象, 而虚函数必须有一张虚表, 但是虚表存在于对象中,静态成员函数既然不属于对象,那么何来的虚表呢, 没有虚表又何谈虚函数呢
类外定义虚函数 只能在声明虚函数的时候在虚函数前面加上一个 virtual 关键字, 当在类外定义的时候, 此时就不能在其前面加上 virtual 关键字

构造函数 构造函数不能为虚函数.

原因是虚函数必须有一张虚表, 但是虚表又存在于对象中, 那么问题来了, 构造函数是为了构造出对象的, 现在对象都没有, 拿来的虚表, 没有虚表拿来的虚函数

父类是虚函数,子类会继续保持,反之不成立

不要在析构函数或者构造函数中调用虚函数

因为在构造函数和析构函数中对象会不完整, 而虚函数的前提是存在于虚表中, 虚表又存在于对象中, 对象不完整,如何找到虚函数呢

最好把基类的析构函数声明为虚函数

class Person
{
    ...
};

class Student:public Person
{
    ...
};

int main()
{
    Person* p = new Student;
    delete p;
    return 0;
}

看到上面的场景中, 我们第一反应就是当我们一次New, 一次delete没有任何问题, 但是问题来了, 如果Student中除了普通成员函数外, Student 对象在析构的时候还需要我们自己去清理, 此时delete的只是父类的对象, 那student中需要清理的内存没有得到清理,此时不就造成内存泄露了吗?
同时注意, 子类和父类的析构函数在编译的时候编译器会将两者处理为相同函数名, 因此当定义为虚函数的时候,此时关注的就是对象了, 在释放的时候会看一下p是一个student的对象,因此会清理student中的东西,此时就不会造成内存泄露了
将析构函数定义为虚函数的目的就是为了在析构的时候当对象是子类的时候清理子类,当对象是父类的时候清理父类,已达到资源正确释放

多态:虚函数指针或引用+父类指针或引用

多态条件
当使用基类指针或者引用调用重写的虚函数的时候,此时指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数

为什么指针和引用可以实现多态而对象不能实现多态

class A
{
public:
    virtual void Debug(){}
};

class B:public A
{
public:
   virtual void Debug(){}
};

void main()
{
    B b;
    A a = b;
    A * point_A = &b;

    a.Debug();
    point_A->Debug();
}

——对于程序A a = b而言,b内存布局在赋值的时候已经从B转换到A了,多于的数据都被丢弃,因此其就是一个A类型变量,那么a.Debug这里的a就是一个A类型的变量。
——对于point_A来说,它是一个指针,其类型虽然是A,但指向的区域的内容却是一个B类型的内存结构,虽然内存结果的布局与A兼容,但其虚函数表中的Debug却是B的实现。

内联函数不能定义为虚函数

虚函数必须有虚表,虚表中存放的是地址,但是内联在编译的过程中会被展开,它没有地址何来的虚表,没有虚表何来的虚函数

调用普通函数比调用虚函数快

因为普通函数就是直接call到一个地址,而调用虚函数得先找到虚表, 然后拿着虚表中的地址再找到虚函数, 因此虚函数是间接寻址, 多了访存次数, 当然也就比普通函数慢了

重写重载重定义的区别

重载 重载函数必须在同一作用域内,满足函数名相同, 参数不同的函数就叫做函数之间构成了重载
重写(覆盖)不同作用域内(基类和派生类)函数名相同, 参数相同, 返回值相同(协变除外), 同时函数前必须有 virtual 修饰
重定义(隐藏) 不同作用域内(基类和派生类)函数名相同, 只要不是重写就是重定义

继承与静态函数

基类中定义了static成员, 则整个继承体系中只有一个static成员, 无论派生出多少个子类, 都只有一个static成员实例

纯虚函数

成员函数形参后面加上 = 0, 此时的成员函数就会变成纯虚函数. 同时包含纯虚函数的类就叫做抽象类(接口类)
纯虚函数只有在派生类中重新定义后才能实例化出对象
抽象类不能实例化出对象

猜你喜欢

转载自blog.csdn.net/qq_41027326/article/details/81075696
今日推荐