bosthhe1 / cpushpush

0 stars 0 forks source link

继承和多态的经典问题+斜变+final+override #26

Open bosthhe1 opened 1 year ago

bosthhe1 commented 1 year ago

1、什么是多态? 多态是不同的对象去做同一件事情,得到不同的结果。 2、什么是重载、重写(覆盖)、重定义(隐藏)? 重载是指函数重载,是静态的多态,函数调用因为函数名相同,参数的个数,顺序,种类不同,返回值相同而构成多态,重写是动态多态,重写是因为子类重写了父类的虚函数,在底层父类有一份虚表,子类如果构成重写,那么子类在重写的虚函数的指针上会进行覆盖,在调用的时候,必须传递指针或者引用才可以,重定义是指子类继承父类成员的时候,由于函数名相同,子类调用函数的时候,会调用自己的函数,如果想要调用父类的函数,需要指定作用域 3、多态的实现原理? 多态是子类重写了父类的虚函数,子类的虚函数会覆盖父类对应的虚函数,底层就是调用的函数不相同 4、inline函数可以是虚函数吗? inline函数可以是虚函数,如果虚函数没有构成多态,那么在编译的时候就确定了是内联函数,如果构成多态,编译器会忽略内敛的特性,变为虚函数,存在虚基表中(值得一提的是,内敛函数会在调用的时候替换,所以内敛函数没有函数地址,类中函数天生就是内敛函数,这里没太理解) 5、静态成员可以是虚函数吗? 静态成员和友元函数都不能是虚函数,因为虚函数调用需要虚函数指针调用(this),而静态成员函数和友元函数都没有this指针,不能可调用到虚函数 6、构造函数可以是虚函数吗? 构造函数不能是虚函数,因为虚函数指针需要在构造的时候初始化,如果构造函数可以是虚函数,那么就需要this指针调用,而this指针是在构造函数的时候初始化,所以无法调用,所以构造函数不能是虚函数 7、析构函数可以是虚函数吗?什么场景下析构函数是虚函数? 析构函数可以是虚函数,在堆上开辟的空间是需要析构函数的虚函数 8、对象访问普通函数快还是虚函数更快? 虚函数在编译的时候就生成虚函数表,如果虚函数不构成重写,那么在编译的时候就会确认地址,普通函数也是编译的时候确认地址,调用的时候就一样快,如果构成重写,就是运行的时候去确定地址(这就是动态绑定),所以普通函数会比虚函数快 9、虚函数表是在什么阶段生成的,存在哪的? 虚函数表和虚函数都是在编译阶段生成的,保存在代码段,但是我看网上说在,因为地址不可变,所以虚函数表存在常量区 10、 C++菱形继承的问题?虚继承的原理? 菱形继承容易造成代码冗余,可以使用虚继承来解这个问题,如果不使用虚继承,那么继承的父类的成员是各自独有一份,如果是虚继承,那么父类的成员是共有的,如果想要访问共有的父类成员,就需要虚基表,虚基表里面存放的是,当前位置和公共成员的指针偏移量,通过偏移量就可以访问成员 11、 什么是抽象类?抽象类的作用? 只要一个类包括了纯虚函数,那么这个类就叫抽象类,抽象类是不能实例化出对象的,作用是要想调用抽象类就必须重写 下面这个func1就是纯虚函数,a这个类叫做抽象类,如果抽象类被击沉后没有重写,那么被继承的类也会称为抽象类 image

bosthhe1 commented 1 year ago

有一点必须注意,接口继承的问题,为了更好的观察接口继承,一般父类会为全缺省参数(虽然是全缺省参数但是也是一个参数),子类需要和父类构成重写,就必须满足参数相同(不管子类是否为全缺省,只要参数个数一样就行)

class e
{
public:
    virtual void fun(int i = 1){ cout <<"A::"<< i << endl; }
};
class f :public e
{public:
    virtual void fun(int i){ cout << "B::" << i << endl; }//这里就是将父类的接口继承下来,子类重
写内容
};
int main()
{
    f b;
    e* p = &b;
    p->fun();
    return 0;
}

image

bosthhe1 commented 1 year ago

斜边是再重写的基础上加的一条条件,如果说子函数重写虚函数中,返回类型为子函数类型的指针,也可以构成重写

class A
{
public:
    virtual A* printf()
    {
        cout << "A->printf()" << endl;
        return &A();
    }
};
class B:public A
{
public:
    virtual B* printf()//返回值不同,但是是返回类的指针,所以也构成重写
    {
        cout << "B->printf()" << endl;
        return &B();
    }
};
void func(A* a)
{
    a->printf();
}
int main()
{
    A a;
    B b;
    func(&a);
    func(&b);
    return 0;
}

image

bosthhe1 commented 1 year ago

final和override final函数写在虚函数后面,表示该虚函数不可被重写,final写在类的后面,表示类不可被继承,override不能跟在类后面只能跟在函数后面 image

image 图中看出A中虚函数重写会报错 override函数表示该函数是否为重写函数,如果没有重写会报错,注意override不能用于基类类,因为基类的类没有重写任何虚函数 NK2@`2BVM4H@Q{7NB 9GENR image