数据抽象
类的基本思想是数据抽象 data abstraction
封装后的类分离了 interface 和 implementation,具体实现时通常都按照分离式编译的原则,在 .h
声明和 .cpp
实现
-
定义类
类本身就是个作用域,类的成员函数定义嵌套在类的作用域中,因此类的成员函数可以直接使用类的数据成员,即使该数据成员定义在函数之后。
不能在类中定义类对象(类未定义完,无法确定类对象存储空间) -
构造函数
初始化类对象的数据成员。未声明任何构造函数时,编译器会自动生成默认构造函数。
初始化方式: 类内(构造函数外)初始化、构造函数初始值列表、构造函数体内部的赋值操作 以及 默认初始化 -
成员函数
类内定义的函数为自动 inline
类内部显式声明 inline,类外的函数定义必须在同一头文件(通常用.inl文件)成员函数可通过 this 访问调用该函数的类对象,此时this为 指向非常量类对象的常量指针
object *const
,指针本身为常量
成员函数参数列表后带const,则修改this为 指向常量类对象的常量指针const object *const
,即函数内部不能改变类对象的内容 -
static 静态变量及静态函数
类对象中不包含任何静态成员的相关数据。静态成员存在于任何对象之外。
static变量不是由构造函数初始化的(即不是创建类对象时初始化)
静态成员函数也不与任何对象绑定在一起(不使用this指针,不能声明为const) -
拷贝、赋值和析构
类的访问控制
-
访问说明符 public、private
class默认成员为private,struct默认成员为public -
友元
有时候需要封装类的数据成员,同时也需要为一部分非类成员函数开放访问权限。友元允许其他类或函数访问其非公有成员,有三种实现方式:
将其他类当作友元class Name { friend class FriendName; }
将辅助函数(非成员函数)当作友元class Name{ friend returnType func(params); }
内部声明表示友元函数对该类有访问权限,但该声明不是函数本身的声明,它自身应有另外的专门声明
将其他类的一个成员函数当作友元 但这种方式需要要特别注意顺序class OtherName { returnType func(...); } // 需首先定义其他类,完成作为友元函数的类成员函数的声明 // 但不能进行函数定义,因为没法使用Name的数据(还没定义) class Name { friend returnType OtherName::func(params); } // 声明友元 returnType OtherName::func(params){...} // 友元函数定义
继承
-
派生类的成员
继承 + 自身定义(两部分不一定连续存储 ) -
访问权限
派生类 继承了定义在基类中的全部成员(不论私有保护公有),只是不一定有访问权限
派生类定义时的访问说明符,决定了 派生类对象(以及派生类的派生类)是否有权限访问继承的基类成员protected成员在派生类的成员函数中 只能通过this访问(而不是通过基类对象访问,因为没有,本质在访问自己继承下来的基类部分)
protected成员不能通过派生类对象访问class Base { returnType func(..); // 直接继承不改变 virtual returnType func(...); // 希望被重写的 public: private: // 基类成员和友元可访问,基类对象不可访问 // 派生类成员不可访问 protected: // 基类成员和友元可访问,基类对象不可访问 private // 派生类成员可访问 public // 派生类对象是否可访问,与定义派生类时的访问控制符相关 } class Derived : public Base { Derived(...) : Base(..), mem(){} }
-
虚函数
通过virtual
关键字,基类将 类型相关函数 与 派生类不做改变直接继承的函数 区分对待
基类的析构函数必须为虚函数
要求 所有虚函数必须有定义(包括基类和派生类),这样运行时才能调用对应版本虚函数函数体
=0
为 纯虚函数(避免具体定义)
包含虚函数的类为 抽象基类 -
final 和 override 关键字
动态绑定 run-time binding
多态 polymorphism 的根本设计原则在于 引用、指针的静态类型和动态类型可以不相同(非引用、指针类其动态与静态类型一致)
静态类型:编译时已知,声明时对象的类型
动态类型:运行时才可知,内存中对象的类型
-
派生类到基类的隐式转换
派生类对象含有与基类对应的部分,因此能把派生类对象当作基类对象使用。即能将基类的指针和引用绑定到派生类对象的基类部分。
基类向派生类不存在隐式类型转换 -
实现动态绑定的条件
使用基类对象的引用或指针调用虚函数。而当通过普通类型的表达式(非指针非引用)调用虚函数,编译时就会把使用版本确定下来。