玩命加载中 . . .

32-公有继承


确定public继承塑模出is-a关系

class Person {...};
class Student: public Person {...};

void eat(const Person& p);            // 任何人都会吃
void study(const Student& s);         // 只有学生才到校学习

Person p;                             // p是人
Student s;                            // s是学生

eat(p);                               // 没问题,p是人
eat(s);                               // 没问题,s是学生,而学生is a人

study(s);                             // 没问题
study(p);                             // 错误,p不是学生

public 继承意味着 is-a。适用于 base class 身上的每一件事情一定也适用于 derived class 身上,因为每一个 derived class 对象也都是一个 base class 对象

避免遮掩继承而来的名称

class Base {
private:
    int x;

public:
    virtual void mf1() = 0;
    virtual void mf1(int) { cout << "Base::mf1(int)" << endl; }

    virtual void mf2() { cout << "Base::mf2" << endl; }

    void mf3() { cout << "Base::mf3" << endl; }
    void mf3(double) { cout << "Base::mf3(double)" << endl; }
};

class Derived: public Base {
public:
    virtual void mf1() { cout << "Derived::mf1" << endl; }
    void mf3() { cout << "Derived::mf3" << endl; }
    void mf4() { cout << "Derived::mf4" << endl; }
};

int main(int argc, char const *argv[])
{
    Derived d;
    d.mf1();    // Derived::mf1
    d.mf2();    // Base::mf2
    d.mf3();    // Derived::mf3
    d.mf4();    // Derived::mf4
    // d.mf1(1);    错误,基类中的方法被覆盖
    // d.mf3(3);    错误,基类中的方法被覆盖
    return 0;
}

base class 中的所有名为 mf1 和 mf3 的函数被 derived class 中的名为 mf1 和 mf3 的函数覆盖。从名字搜索的观点看,Base::mf1 和 Base::mf3 不再被 Derived 继承

可以使用using声明式

class Derived: public Base {
public:
    using Base::mf1;    // 让Base内的mf1和mf3的所有东西
    using Base::mf3;    // 在Derived作用域内可见
    virtual void mf1();
    void mf3();
    void mf4();
};

这意味着如果你从一个带有重载函数的 base class 继承,而且你只想重定义或替换它们中的一部分,你需要为每一个你不想覆盖的名字使用 using declaration。如果你不这样做,一些你希望继承下来的名字会被覆盖

如果是 private 继承,可能会只想继承函数的某个版本,这时就不能用 using 了,可以使用转交函数

class Base {
private:
    int x;

public:
    virtual void mf1() { cout << "Base::mf1" << endl; }
    virtual void mf1(int) { cout << "Base::mf1(int)" << endl; }
};

class Derived: private Base {
public:
    virtual void mf1() {    // 转交函数,forwarding function
        Base::mf1();
    }
};

int main(int argc, char const *argv[])
{
    Derived d;
    d.mf1();    // Base::mf1
    // d.mf1(1);    // 错误,Base::mf1(int)被遮掩了
    return 0;
}
  • derived classes 中的名字覆盖 base classes 中的名字,在 public 继承中,这不是我们想要的
  • 为了使隐藏的名字重新可见,使用 using declarations 或者 forwarding functions

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录