CS100:C++面向对象学习笔记
CS100: C++面向对象学习笔记
CS100上学习的面向对象内容更为详细,也更为复杂。尽管这门课的进度相比SI100B已经放缓了不少,但由于我没有学习的基础,因此打算写一份笔记。
面向对象的编程主要具有三个特点:Encapsulation(封装)、Inheritance(继承)和Polymorphism(多态)。在SI100B中我们大概只学习了encapsulation,而剩下的内容会较为详细地记录。
杂项
Code Organization
Complication
Static
Encapsulation/封装
封装的目的是为了隐藏信息及抽象化,达成分离interface(接口)和implementation(实现),从而能在使用interface的同时不需要知道任何有关implementation的内容。
这部分内容在SI100B中已经有过学习,更新可能比较随缘。
Classes: Morphing from Struct/类
相比C中的structs(在C++中,class和struct实际上差别不大),classes有member functions(成员函数),这些fxns会在类的declaration(声明)中。
在类外实现时,成员函数的声明遵循如下格式:
ClassName::FunctionName
它们能够直接访问类中的所有member variables(成员变量)。
使用类时,相当于创造了一个类的instance(实例),它是类的type的一个对象。
Access/访问
Access Specifier/访问说明符
类中对象的默认specifier是private。
Member Functions/成员函数
Overload/重载
Constructor/构造函数
Inheritance/继承
Object Relationship/对象关系
C++中对象的关系有两种:inheritance和association,其中association又分为composition和aggregation。
Inheritance/继承
一个类继承的类是它的父类/基类(parent class/base class/superclass),它是那个类的子类/派生类(child class/derived class/subclass)。inheritance的格式是
class childClassName: public parentClassName
实际上inheritance可以通过private和protected完成。
可以进行多重inheritance,即一个child class有多个parent class。
child class可以use(使用parent的behaviours),extend(创建新的behaviours)和replace(override parent的behaviours)。
继承的对象是parent class的public fxns&vars,protected fxns&vars和private vars,但private vars不可以直接被child class访问。如果child希望访问private vars,可以通过访问protected fxns的方式与这些变量进行交互。
Overriding
overloading和overriding的区别是,overloading是使用相同的函数名,但对于每个overloaded implementation有不同的参数;而overriding是使用相同的函数名和参数,但有不同的implementation。
overriding只可能通过inheritance实现。
值得注意的是,overriding的fxn可以直接通过scope resolution operator(域解析运算符,即::)调用parent的原fxn。
Overloading
overriding的优先级(precedence)比overloading高,所以编译器会优先尝试overriding。这意味着如果直接写了不同的参数,可能不会达到期望的效果。
为了overload,我们需要
returnType childClassName::functionName(variableType variableName);
returnType childClassName::functionName(variableType1 variableName1,variableType2 variableName2);
这样,上面完成了overriding,下面完成了overloading。
Composition/
composition是指parent class包含了child class,并且如果parent class is destroyed,那么child class is also destroyed。composition的格式是
class parentClassName
{
childClassName m_childClassName;
}
Aggregation/
aggregation是指parent class链接向child class,因此即使parent class is destroyed,child class也不会be destroyed。我们需要用pointer实现这一效果。aggregation的格式是
class parentClassName
{
childClassName *m_childClassName;
}
Polymorphism/多态
多态指的是给予不同的对象一个相同的接口,通过这个接口用type independent(待理解)的方式去操作(manipulate)这些对象。可以通过subtyping的方式做的更多,这又被称为inclusion polymorphism,我个人认为也就是我们正在学习的polymorphism。在C++中,这通过类的inheritance、overriding和virtual function来实现。
Limitation/限制
父类并不是继承子类,因此用父类的指针指向子类对象(的引用)并不能使用子类新增的方法。
Virtual Function/虚函数
可以通过虚函数让允许(grant)父类直接访问子类的methods。虚函数是C++实现late binding(晚绑定)的方式,适用于父类创建时子类实现是未知的或者可变的。
Late Binding/晚绑定
即绑定在运行时决定,而非(as opposed to)编译时。
Using Virtual Function/使用虚函数
在父类里声明函数时
virtual returnType fxnName();
即可。只需要对prototype(原型)对象(待理解)使用virtual
,即不要
virtual returnType ClsName::fxnName();
对应的子类函数不再需要virtual
关键字,但是for clarity's sake还是可以加上它。
Abstract Classes & Function Types/抽象类和函数类型
上一节中的父类函数必须要有实现,子类则可以选择是否override,如果否就会直接使用父类的定义。
如果声明函数时
virtual reurnType fxnName()=0;
那么这个函数的类型变成了pure virtual(纯虚),即父类函数没有实现,子类必须要有实现。
此时父类变成了abstract class(抽象类),无论其他函数是什么。抽象类无法声明抽象类对象(即无法实例化),其只能被当作基类使用。
Virtual Function Tables/虚函数表
当我们使用多态时,编译器使用虚函数表,即它为有虚函数的类及它的子类创建。
每一个类的实例对象都有一个隐藏的指针变量,它会指向该类的虚函数表,而这个虚函数表中列出了类里所有虚函数的地址。
Virtual Destructors/Constructors|虚析构函数/构造函数
Virtual Destructors/虚析构函数
每一个包含虚函数的类都需要包含一个虚析构函数,因为非虚(non-virtual)析构函数只会调用基类的析构函数。
Virtual Constructors...?/虚构造函数......?
没有虚构造函数。
因为多态和虚函数是用于在不知道类型或者没有对象的完整信息的情况下操作对象的,而如果我们构造一个对象,我们就拥有了完整的信息,因此没有理由使用虚构造函数。
Copy Constructor/复制构造函数
References as Class Members/类的引用成员
这些成员在声明时没有初值,但它们必须在构造函数的初始化列表里初始化,且对应的构造函数的形参必须也是引用类型。
Returning References/返回引用
函数是可以返回引用的,这么返回甚至可以给它赋值。但是它们必须引用(refer to)非局部(non-local)变量。
Const in Function Arguments(typo: Parameters?)/函数形参中的常量
不要传递常值,一般传递常引用。const
修饰符可以使得对象不被修改,且比传递值更有效率。