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

C++ Primer(五)_OOP_数据抽象

时间:2019-10-20 01:07:36      阅读:98      评论:0      收藏:0      [点我收藏+]

标签:接口   cpp   interface   实参   div   abstract   精确   类型   tab   

数据抽象——类

类的基本思想——数据抽象(data abstraction)与封装(encapsulation)

数据抽象:一种依赖于接口(interface)与实现(implementation)分离的编程与设计技术

类的接口——用户所能执行的操作

类的实现——数据成员、负责接口实现的函数体及所需的各种私有函数

封装:实现类的接口与实现分离

封装的意义

  • 防止用户代码对封装对象的封装
  • 调整封装类的细节而无需调整用户代码

编译器对类的处理顺序

  1. 先编译所有成员声明
  2. 再编译所有成员实现——所以可以随意使用成员而无需在意顺序

构造函数

  • 不可定义为const

    const对象的常量属性的获得在构造函数完成初始化过程,所以const对象初始化期间可以修改

  • 默认构造函数

    • 无参数
    • 或都有默认实参
  • 未显示定义构造函数,编译器将合成默认构造函数

    • 若有类内初始值,这个构造函数将初始化对应成员(类内初始值由编译器支持)
    • 无初始值,执行默认初始化(有默认构造函数的类成员就默认构造,内置类型的默认初始化根据所在区域:全局0,局部未定义)——类内初始值以=或花括号形式赋予
  • 委托构造函数——初始化列表调用其他构造函数——执行顺序为完全执行被委托者后返回委托者

  • 初始化顺序——取决于类内声明顺序——与初始化列表无关——所以不要在初始化列表做一些依赖于顺序的事

成员函数的定义

类内定义——隐式inline
类外定义
  • inline可同时出现在内外

  • vitual只能出现在类内

  • const类内外都要出现——因为其修饰的是this指针所指,而底层const是可以形成重载的,所以如果不带const,会发现没这个成员

    顶层const:修饰的是对象本身,对象本身不可变,初始化它的对象既可以是const也可以非const

    void f(int);
    void f(const int);    // 错误,重定义,两者不能形成重载
    // 理由:函数匹配的实参转换等级中,1.实参形参类型相同;和2.向实参添加或删除顶层const都属于精确匹配(另一个精确匹配是实参数组或函数转为形参指针)

    底层const:变量自认为初始化的对象是不能改变的,初始化它的对象既可以是const也可以非const

    但是,底层const能与非底层const形参能形成函数重载

    void f(int *);
    void f(const int *);  // 正确
    // 理由:能对底层和非底层区分
    // 1.底层const不能隐式转换为非const,即const int* 不能隐式转换为int*,首先对const int*实参就确定调用哪个
    // 2.转换等级中:int *到const int *的转换等级比精确匹配低一级,所以对int *实参能确定调用哪个
  • =default可出现在类内也可出现在类外,且只能出现一处,类内为内联,仅用于拷贝控制成员

  • =delete,必须出现在第一次声明的时候,可用于各种函数

  • static只用于内部

const成员函数
  • const对象只能调用const成员函数

  • 非const对象也能调用const成员函数

  • 既定义const又定义非const的(既然非const对象能调用const成员,为什么费劲再写个const)一个理由:const修饰的是this指针所指,所以如果需要返回对象,const只能返回const对象,对非const对象略微便

  • const成员函数不能修改类成员,如若实在需要修改(如做些记录……):声明数据为mutable

    一个现实的例子:

    lambda表达式生成一个无名类的const临时对象

    而它的捕获列表实际是其类成员,

    函数体实际是一个const成员函数,

    所以如果lambda表达式需要修改捕获列表的值,就需要声明为mutable

类的前向声明——incomplete type

仅作声明而无定义:class Name;

因为定义,不知道有何成员,所以

  • 定义该类型的指针或引用

  • 亦可声明(不可定义——定义要在类定义之后)以其为参数或返回值的函数

    class A;
    void test(A a);       // 正确

友元——拥有与类内成员访问同样权限的对象

  • 友元类

    • 不可继承,即友元类不能随意访问派生
    • 不可传递,即A为B友元,B为C友元,不能得到A为C友元
    class A
    {
        friend class B;   // 不要求声明于前
    };
    class B
    {
    };
  • 友元函数

    • 普通函数友元——友元声明仅指定访问权限不是实际意义的函数声明,若希望类用户可调用友元。需要类外专门声明

      虽然大多编译器不强制要求如此规则

      // void f();
      class A
      {
          friend void f() { /* 友元函数可在类内定义,但是即使是内部函数调用,也需要声明 */ }
          // 友元声明仅是隐式的假定f()可见,但事实这里并没有
          // 错误,未声明 A() { f(); }  // 若想要其正确,必须在A定义前声明f()
      };
      • 重载的函数需要每个声明为友元(如果有需要的话)
      void f();
      void f(int);
      class A
      {
          friend void f();
          friend void f(int);
      };
    • 成员函数友元——(这里假定这个函数是要访问类的,不然有何意义)

      class B;        // 不可定义,因为此时A并不可见——(如果是普通的函数到不在意)
      class A
      {
      public:
          void f(B);  // 不可定义,因为B还未定义,不知其内容
      };
      class B
      {
          friend A::f();
      };
      void A::f(B)        // 此时才知道B的内容
      {}
  • 友元模板

  • 友元模板特例

  • 甚至友元内置成员(虽然无实际用处,但允许这么做)

C++ Primer(五)_OOP_数据抽象

标签:接口   cpp   interface   实参   div   abstract   精确   类型   tab   

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

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