C++:91---类继承(继承中类的作用域(附加:隐藏、重写(覆盖)))

一、派生类的作用域嵌套在其基类的作用域之内

  • 例如:有下面的代码
class Quote {
public:
    double isbn() {
        return 3.14;
    }
};

class Disc_quote :public Quote {};

class Bulk_quote :public Disc_quote {};

int main()
{
    Bulk_quote bulk;
    cout << bulk.isbn();
    return 0;
}
  • bulk对象在调用isbn()函数时,会:
    • 从Bulk_quote类中查找是否有该函数,发现没有
    • 进一步查找Disc_quote类,发现Disc_quote类中也没有该函数
    • 进一步查找Quote,发现存在,于是执行Quote中的isbn()函数

二、在编译时进行名字查找

  • 一个对象、引用、或指针的静态类型决定了该对象的哪些成员是可见的。即使静态类型与动态类型可能不一致(例如使用基类的指针/引用指向于派生类)
  • 举个例子:
class Quote {};

class Disc_quote :public Quote {
public:
    std::pair<size_t, double> discount_policy()const {}
};
class Bulk_quote :public Disc_quote {};

int main()
{
    Bulk_quote bulk;
    Bulk_quote *bulkP = &bulk;
    Quote *itemP = &bulk;

    bulkP->discount_policy();  //正确,bulkP的类型是Bulk_quote
    itemP->discount_policy();  //错误,itemP的类型是Quote
    return 0;
}
  • 上述代码错误的那一行是因为使用基类的指针指向于派生类,但是通过这个指针调用了属于派生的成员(但是基类中没有定义),该成员对于基类来说是不可见的

三、隐藏

四、虚函数的隐藏

  • 通过隐藏的知识点我们知道,虚函数为什么在基类与派生类中的参数列表必须一致了。如果参数列表不一致,那么基类的虚函数在派生类中没有被重写,而是被隐藏了(就无法通过基类的引用或指针调用派生类的虚函数了)
  • 注意:此处介绍的是虚函数的隐藏,而不是重写(覆盖)

演示案例

class Base {
public:
    virtual int fcn();  //虚函数
};

class D1 :public Base {
public:
    //因为参数列表不一致,因此Base的虚函数没有被覆盖(重写),而是被隐藏了
    //所以下面的fcn函数时D1的一个普通成员函数,不是虚函数
    int fcn(int);
    virtual void f2(); //虚函数
};

class D2 :public D1 {
public:
    int fcn(int); //非虚函数,隐藏了D1::fcn(int)
    int fcn();    //覆盖了Base的虚函数fcn()
    void f2();    //覆盖了D1的虚函数f2()
};
  • 下面都是对虚函数的调用
int main()
{
    Base bobj;
    D1 d1obj;
    D2 d2obj;
    Base *pb1 = &bobj;
    Base *pb2 = &d1obj;
    Base *pb3 = &d2obj;

    pb1->fcn(); //虚调用,运行时调用Base::fcn()
    pb2->fcn(); //虚调用,运行时调用Base::fcn()
    pb3->fcn(); //虚调用,运行时调用D2::fcn()

    D1 *d1p = &d1obj;
    D2 *d2p = &d2obj;

    d1p->f2(); //虚调用,运行时调用D1::f2()
    d2p->f2(); //虚调用,运行时调用D2::f2()
    return 0;
}
  • 还有以下对于非虚函数fcn(int)的调用
int main()
{
    D2 d2obj;
    Base *p1 = &d2obj;
    D1   *p2 = &d2obj;
    D2   *p3 = &d2obj;

    //错误p1->fcn(42); Base没有用fcn(int)函数
    p2->fcn(42); //静态绑定,调用D1::fcn(int)
    p3->fcn(42); //静态绑定,调用D2::fcn(int)
	return 0;
}

五、重载函数与隐藏、重写(覆盖)的关系

  • 从上面的隐藏知识点来看,对于派生类的函数,不论是成员函数还是虚函数都可以被重载
  • 有时一个基类有很多重载函数,而派生类重写了基类的函数,那么默认情况下,基类中的这些所有的重载函数都不可以使用了。见下面的演示案例:
class A {
public:
    void func();
    void func(int);
    void func(string);
};

class B :public A {
public:
    void func(); //此时A中的三个func都被覆盖了,只能使用无参数的func版本
};

int main()
{
    B b;
    b.func();       //正确
    //b.func(10);   错误
    //b.func("HelloWorld"); 错误
    return 0;
}

使用using声明

  • 如果我们希望只覆盖基类中的一部分函数,而其他函数在派生类中还没有被覆盖,一种使用方法就是使用前面文章介绍的using声明。这样的话就无须覆盖基类中的每一个重载版本了
  • using声明只需要给出名称,而不需要给出参数列表,因此基类中的所有重载函数在派生类中都可以使用了
  • 注意:使用using声明时,当using在派生类的不同的访问模式(public、protected、private)下,那么基类的函数在派生类中就属于该访问模式
  • 演示案例:
class A {
public:
    void func();
    void func(int);
    void func(string);
};

class B :public A {
public:
    void func();
    //使用using声明,此时只有无参数的func被覆盖了,而另外两种func在派生类中没有被覆盖
    //using处于public下,因此三个func函数都是public的
    using A::func;
};

int main()
{
    B b;
    b.func();            //正确
    b.func(10);          //正确
    b.func("HelloWorld");//正确
    return 0;
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值