从C到C++学习笔记3: C++面向对象

从 C 语言到 C++ 语言的修炼之路,最重要的一个阶段就是面向过程的编程模式向面向对象编程模式的转变,本文主要记录 C++ 面向对象最终的概念和基本实现。

C++ 类和对象

C++ 类成员函数

类的成员函数是指那些把定义和原型写在类定义内部的函数。类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员。

也可以在类的外部使用范围解析运算符 :: 定义该函数:

调用成员函数是在对象上使用点运算符(.)

类访问修饰符

公有成员 (public)在程序中类的外部是可访问的。
私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。

类的构造函数

构造函数的名称与类的名称相同,也不会返回 void, 也不会返回任何类型。它会在每次创建类的新对象时执行。带参数的构造函数可用于为某些成员变量设置初始值。

使用初始化列表来初始化字段

假设有一个类 C,具有多个字段 X、Y、Z 等需要进行初始化,可以采用初始化列表来初始化字段:

等价于:

类的析构函数

析构函数的名称与类的名称相同,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源,它会在每次删除所创建的对象时执行。

C++ 拷贝构造函数

拷贝构造函数使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数。
  • 复制对象,并从函数返回这个对象。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。
如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。

C++ 友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。友元函数不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:

声明类 ClassTwo 的所有成员函数作为类 ClassOne 的友元,需要在类 ClassOne 的定义中放置如下声明:

C++ 内联函数

如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。

在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。

C++ this 指针

每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。
友元函数没有 this 指针,因为友元不是类的成员。
只有成员函数才有 this 指针。

C++ 类的静态成员

使用 static 关键字来把类成员定义为静态的。当声明类的成员为静态时,无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。静态成员初始化不能放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化。

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。

静态成员函数只能访问静态数据成员,不能访问其他静态成员函数和类外部的其他函数。

静态成员函数有一个类范围,他们不能访问类的 this 指针。使用静态成员函数来判断类的某些对象是否已被创建。

C++ 继承

基类和派生类

访问控制

访问 public protected private
同一个类 yes yes yes
派生类 yes yes no
外部的类 yes no no

一个派生类继承了所有的基类方法,但下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。

集成类型

  • 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
  • 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
  • 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

C++ 重载

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载运算符重载
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

C++ 多态

C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。

虚函数

虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。

纯虚函数

有时候需要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。

= 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数。

C++ 接口(抽象类)

C++ 接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念。
如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。

设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。

参考

  1. W3Cschool C++教程
  2. 菜鸟教程 C++教程

版权声明

  1. 本文由 Howie Lee 发表,采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。请确保你已了解许可协议,并在 转载 时声明。
  2. 转载请注明来源,本文固定链接:http://www.lifower.com/?p=151

——文章采用PyPoster离线发布,欢迎到GitHub支持原作者!