【C++Primer】15.5 访问控制与继承 & 15.6 继承中的类作用域

15.5 访问控制与继承

受保护的成员

派生类中的成员或友元只能通过派生类对象来访问基类的受保护成员。派生类对于一个基类对象中的受保护成员没有任何访问特权。

class son: public father
{
public:
    son() = default;
    son(const string &_name): father(_name) { }
    void show() const override
    {
        father ff("ff");
        // 下列语句会报错,因为name在基类father中是protected的,只能通过派生类对象来访问。
        cout << ff.name << endl;   
    }
};
公有、私有和受保护成员

派生访问说明符不会影响派生类成员对基类成员的访问权限,派生类中仍然只能访问基类中的public和protected成员。

派生访问说明符的目的是控制派生类用户(或者说类对象)(包括派生类的派生类在内)对于基类成员的访问权限。

  • public继承方式
    • 基类中的public成员在派生类中仍为public;
    • 基类中的protected成员在派生类中仍为protected;
    • 基类中的private成员在派生类中被继承下来,但是不可访问;
  • protected继承方式
    • 基类中的public成员在派生类中变为protected属性;
    • 基类中的protected成员在派生类中变为protected属性;
    • 基类中的private成员在派生类中被继承下来,但是仍不可访问;
  • private继承方式
    • 基类中的public成员在派生类中变为private属性;
    • 基类中的protected成员在派生类中变为private属性;
    • 基类中的private成员在派生类中被继承下来,但是仍不可访问
派生类向基类转换的可访问性

感觉没啥好看的。

友元与继承

友元关系不能继承。

改变个别成员的可访问性

使用using声明可以改变成员的访问权限。注意派生类只能为它可以访问的名字提供声明,基类中的private不可以。

默认的继承保护级别

默认情况下,使用class关键字定义的派生类是私有继承的,使用struct关键字定义的派生类是公有继承的。

struct和class唯二的差别:

  • 默认成员访问说明符:struct public,class private。
  • 默认派生访问说明符:struct public,class private。

15.6 继承中的类作用域

当存在继承关系时,派生类的作用域嵌套在其基类的作用域之内。如果一个名字在派生类的作用域内无法正确解析,则编译器会继续在外层的基类中寻找该名字的定义

Bulk_quote bulk;
cout << bulk.isbn(); 	

比如上述isbn()的解析过程将如下:

  • 先在Bulk_quote中查找isbn,没找到,去基类Disc_quote中找。
  • Disc_quote也没找到,继续去基类Quote中找。
  • Quote找到,所以使用的isbn最终被解析为Quote中的isbn
在编译时进行名字查找

一个对象、引用或指针的静态类型决定了该对象的哪些成员是可见的。所以说是在编译时进行名字查找。

Bulk_quote bulk;
Quote *itemP = &bulk;
itemP->discount_policy();   // 错误

通过itemP调用discount_policy()非法,itemP的静态类型是Quote,通过itemP只能访问到bulk中的Quote部分。
可以理解为item只绑定到了bulkQuote部分,自然访问不到其它部分。

名字冲突与继承

派生类的成员将隐藏同名的基类成员。可以通过作用域运算符来使用隐藏的成员。

名字查找优先于类型检查

如果派生类(即内层作用域)的成员与基类(即外层作用域)的某个成员同名,则派生类将在其作用域内隐藏该基类成员。即使形参列表不一样,也会被隐藏。

struct Base{
    int memfcn();
}

struct Derived: Base {
    int memfcn(int n); // 会隐藏基类的memfcn
}

Derived d; Base b;
d.memfcn(); // 错误								

当在派生类中找到memfcn时,名字查找就已经结束,当前调用的版本需要一个int,而当前调用没有提供参数,错误。

虚函数与作用域

现在可以理解为什么基类与派生类的虚函数必须有相同的实参列表了。假如基类与派生类的虚函数接受的实参不同,则我们就无法通过基类的引用或指针调用派生类的虚函数了。

个人理解:当通过一个基类的指针或引用调用派生类的虚函数时,相当于这个基类指针绑定到了派生类中的基类部分。

  • 调用虚函数时会发生动态绑定,会选择派生类的版本。因为派生类对基类中的虚函数进行了重写(“覆盖”),此时派生类中没有基类版本的虚函数,而基类指针则会把这个当成是基类的虚函数进行绑定。
  • 调用非虚函数时不会发生动态绑定,实际调用的版本由指针的静态类型决定。

粗略地说调用虚函数时也是由静态类型决定的,只不过派生类对象中基类的虚函数被重写成了派生类版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值