码迷,mamicode.com
首页 > 编程语言 > 详细

C++ Primer(六)_OOP_继承

时间:2019-10-20 00:54:42      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:继承   提高   变量   str   可见   private   重写   lis   无法   

目录

继承

定义相似的类型并对其建模,形成一种层次关系
基类——一般、泛化

派生类——具体、细化

继承的意义

  • 实现代码重用
  • 提高软件易扩展性

Best Practices

为基类定义虚析构函数

理由:

当delete一个动态分配的对象指针时,将执行析构函数,如果指针指向的是继承体系的类型,

可能出现指针的静态类型与动态类型不符的情况

此时将可能调用了错误版本的析构函数,产生未定义行为

又提重载Overloaded、覆盖(重写)Override与隐藏

  • 重载: 同一作用域,函数名相同而形参列表不同

  • 覆盖: 派生类对继承来的函数进行重新定义——对函数体的修改

  • 隐藏: 内层作用域定义同名函数,形参列表随意——即使形式上能与外层作用域同名函数形成重载,但实际上在内层作用域中,能看到的仅有此函数,外层同名者被隐藏

    类的继承会形成一个嵌套关系:基类为外层作用域,派生类为内层作用域,

    可用using形成重载

    若产生冲突(参数列表一样),将优先调用内层作用域所定义的

可继承的基类

必须被已被定义,

因为派生类需要它的成员,

同时另一个隐含——类不能派生自自身

访问控制

class和struct的区别仅为类成员的默认访问权限与默认继承权限,前者为private,后者为public

  • 类成员权限控制符——控制用户(普通用户和派生类)的访问权限

    • private:用户不可访问

    • protected:普通用户不可访问,派生类及派生类友元可访问

      派生类成员和派生类友元只能通过派生类对象(类内仅是省略了this)访问基类protected成员,而不能通过基类对象访问

      class A
      {
      protected:
          int a;
      };
      class B
      {
      public:
          void f(A a) { a.a; }    // 错误,不能通过基类对象访问
          void f() { a; }         // 正确,实际也是this->a;
          void f(B b) { b.a; }    // 正确
      };
    • public:任何用户都可访问

  • 类继承权限控制符——控制派生类的用户(普通用户和派生类的派生类)的访问权限——对派生类没有影响

    • private:派生类的用户不可访问任何成员
    • protected: 普通用户不可访问任何成员——基类中public在派生类被降为protected
    • public:与类内权限相关
  • 继承权限控制——派生类到基类的转换

    派生类到基类的转换:基类指针或引用指向派生类

    • 用户代码
      • private和protected:不能使用A *ap = new B; // 如果可行,那么用户代码就突破了private和protected的限制,通过ap访问B中本不可访问成员
      • public:可以使用
    • 派生类和派生类友元
      • 无影响
    • 派生类的派生类
      • private:不能使用,理由类似用户代码
      • protected和public:可以使用

类型转换

智能指针也支持派生类到基类的转换

静态类型:编译时已知,由变量声明时类型或表达式生成的类型确定

动态类型:运行时可知,对象或表达式在内存中的类型

继承体系中,基类的指针或引用能绑定到派生类对象上,所以其静态类型和动态类型可能不一致

一个对象、引用或指针的静态类型决定了其可见成员

作用域

一个类定义自己的作用域

继承体系中:派生类的作用域嵌套与基类的作用域中

  • 名字查找——由对象的静态类型确定查找的作用域

    • 确定静态类型
    • 到静态类型对应的类查找,无果,往上到直接基类直至找到活到达顶端报错
    • 找到后常规类型检查,调用是否合法,重载

    • 若合法,根据是否为虚函数

      • 虚函数且通过指针或引用调用,运行时确定函数版本,依据转为动态类型
      • 非虚函数或普通对象调用,直接产生常规函数调用
  • 隐藏:内层同名隐藏外部同名——即使能产生重载,也no matching

    ? 若希望形成重载,使用using 将外层作用域函数引入内层作用域

    ? 若产生冲突(参数列表一样),将优先调用内层作用域所定义的

阻止继承的方式

C++11:final关键字
class NoDerived final { /* */ };

class Base { /* */};
class Last final : Base { /* */ };

辅助类

class A;
class Assistant
{
private:
    Assistant();
    friend class A;
};

class A : public virtual Assistant  // 虚拟继承理由:
                    // 非虚拟继承时,B构造调用A构造,A调用Assistant构造,可正常进行,无法阻止继承
                    // 虚拟继承时,Assistant的构造函数将由B寻址调用,private无法进行
{
};

class B : public A
{
public:
    B(){}   // 实际不自己定义,编译器将合成一个deleted的默认构造函数
};

int main()
{
    A a;
    B b;                // 错误,Assistant::Assistant() is private in this contex
}

C++ Primer(六)_OOP_继承

标签:继承   提高   变量   str   可见   private   重写   lis   无法   

原文地址:https://www.cnblogs.com/YanceW/p/11706328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!