C++_继承&多态

三种继承关系
1.公有public继承
基类为public,派生类也是public,基类为protected,派生类也是protected,基类为private,派生类为不可见。
2.保护protected继承
基类为public,派生类为protected,基类为protected,派生类也是protected,基类为private,派生类为不可见。
3.基类为public,派生类为private,基类为protected,派生类也是private,基类为private,派生类为不可见。

有基类成员不希望被直接访问,又希望能被派生类访问,就出现了保护成员,保护成员不能直接访问,因此保护成员限定符是因为继承才出现的。
继承与转换(public继承)

子类对象可以赋值给父类对象(切片)
父类对象不能复制给子类对象
父类的指针或引用可以指向子类对象
子类的指针或引用不能指向父类的对象(可以强制类型转换)
继承中,基类和派生类有独立的作用域
父类子类有同名成员时(函数只需要名字相同),子类将屏蔽父类对成员的直接访问——重定义(最要不要定义同名成员)

单继承
001
菱形继承
002
菱形继承问题:数据冗余和二义性
解决方法:虚继承
003
虚函数&多态
虚函数: 类的成员函数前面加virtual关键字,则这个成员为虚函数。
虚函数重写: 当在子类定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数。

重写需要函数名、参数列表、返回值完全i相同(协变除外)
基类定义了虚函数,则在派生类中该函数始终保持虚函数特性。
只有类的成员函数才能定义为虚函数,如果在类外定义,只需要声明时加virtual,类外定义不能加。
静态成员函数、友元函数、构造函数、内联函数不能定义为虚函数,且构造函数最好不要调用需虚函数。
operator=可以定义为虚函数,但是最好不要这样做,使用时容易混淆。
最好把基类的析构函数声明为虚函数,因为编译器特殊处理,析构函数构成覆盖。

继承中同名成员函数的关系
1.重载

在同一作用域
函数名相同,参数不同
返回值可以不同

2.重定义(隐藏)

在不同作用域
函数名相同
基类和派生类中,不构成重写,就是重定义

3.重写(覆盖)

在不同作用域(分别在基类、派生类)
函数名、参数、返回值都相同
基类函数必须有virtual关键字
访问修饰符可以不同

多继承中虚函数及虚表的保存
非菱形继承
虚表指针保存在第一个继承类的首位置
004
005
非虚继承菱形继承

class A
{
public:
    virtual void fun()
    {
        cout << "funa()" << endl;
    }
    virtual void funaa()
    {
        cout << "funaa()" << endl;
    }
    int _a;
};

class B : public A
{
public:
    virtual void fun()
    {
        cout << "funb()" << endl;
    }
    virtual void funbb()
    {
        cout << "funbb()" << endl;
    }
    int _b;
};

class C : public A
{
public:
    virtual void fun()
    {
        cout << "func()" << endl;
    }
    virtual void funcc()
    {
        cout << "funcc()" << endl;
    }
    int _c;
};

class D : public B, public C
{
public:
    virtual void fun()
    {
        cout << "fund()" << endl;
    }
    virtual void fundd()
    {
        cout << "fundd()" << endl;
    }
    int _c;
};

006
与多继承类似

虚继承菱形继承
007
虚基表指针在虚表指针下面,3个虚表,B类和C类各一个虚表,保存各自的虚函数,第3个虚表保存A类的虚函数,而D类的虚函数保存在第一个继承的类B的虚表中。

猜你喜欢

转载自blog.csdn.net/cute_shuai/article/details/80092877