一、class声明与定义

  • 基本结构: class声明包含class head和class body两部分,其中body包含成员函数和数据成员

  • 声明与定义关系: 在class body内直接实现的函数既是声明也是定义,如real()imag()函数;仅有声明无定义的函数需在外部实现,如operator+=

  • 数据封装: 数据成员reim被声明为private,实现封装

二、class template简介



00:31



  • 模板语法: 使用template<typename T>声明模板类,将特定类型参数化

  • 类型替换: 原double类型被替换为模板参数T,如complex<double>complex<int>实例化

  • 应用场景: 适用于需要支持多种数据类型但逻辑相同的类结构

三、inline函数



01:34



1. 定义与特性
  • 自动inline: 在class body内直接定义的函数自动成为inline候选,如real()imag()

  • 显式inline: 外部定义的函数可通过inline关键字建议编译器内联,如imag(const complex& x)

  • 编译器决定权: inline只是对编译器的建议,最终是否内联由编译器决定

2. 优点与局限性
  • 执行效率: 消除函数调用开销,执行更快

  • 代码膨胀: 复杂函数内联可能导致代码体积增大

  • 编译器限制: 函数过于复杂时编译器可能拒绝内联

3. 使用建议
  • 适用场景: 简单、频繁调用的函数适合inline

  • 最佳实践: 在class内部定义简单函数,复杂函数在外部实现

四、访问级别

1. 基本概念
  • public: 对外公开的接口,如成员函数real()imag()

  • private: 仅类内部可访问,如数据成员reim

  • protected: 保护成员(本课程未涉及)

2. 封装原则
  • 数据隐藏: 所有数据成员应声明为private

  • 访问控制: 必须通过public成员函数访问私有数据

  • 错误示例: 直接访问c1.re会导致编译错误

3. 使用规范
  • 段落组织: public/private区域可交替出现

  • 函数分类: 外部接口放public,内部辅助函数可放private

  • friend例外: friend函数突破封装限制,需谨慎使用

五、构造函数



10:03



1. 基本概念与示例



10:21



  • 自动调用机制: 创建对象时自动被调用,无需手动调用。例如创建complex c1(2,1)complex c2complex* p = new complex(4)时都会自动调用构造函数。

  • 命名规则: 必须与类名完全相同,如complex类的构造函数必须命名为complex

  • 无返回值: 构造函数不需要返回类型,因为其唯一目的就是创建特定类的对象。

  • 初始化列表: 使用冒号语法:re(r),im(i),这是构造函数特有的初始化方式,效率高于赋值方式。

  • 赋值方式: 在函数体内通过re=r; im=i;赋值,虽然结果相同但效率较低。

  • 两阶段初始化: 变量初始化分为初始化阶段(初始化列表)和赋值阶段(函数体内),前者效率更高。

2. 重载与默认参数



20:29



  • 默认参数: 如complex(double r=0, double i=0),创建对象时可不传参使用默认值,如complex c2会使用0初始化。

  • 重载规则:

    • 函数名相同但参数不同(类型或数量)

    • 编译器会将函数名和参数类型编码成唯一标识

    • 示例中real()real(double r)可以共存

  • 冲突情况: 当默认参数构造函数与无参构造函数同时存在时会产生歧义,如complex()complex(double r=0, double i=0)不能共存。

  • 名称修饰: 编译器会将函数名和参数类型编码成类似?real@Complex@@QBENXZ的内部名称实现重载。

  • 设计建议:

    • 优先使用初始化列表

    • 合理使用默认参数减少重载数量

    • 避免会产生歧义的重载组合

3. 析构函数说明
  • 适用情况: 对于不带指针成员的类(如本例的complex),通常不需要自定义析构函数。

  • 分类原则: 类可分为带指针和不带指针两类,前者通常需要自定义析构函数进行资源释放。

六、知识小结

知识点

核心内容

考试重点/易混淆点

难度系数

类的定义与声明

类(Class)需包含数据成员和成员函数,可通过public/private区分访问权限

publicprivate的作用域区分,数据封装的意义

⭐⭐

inline函数

在类本体定义的函数默认为inline,编译器可能优化为内联,但复杂函数可能无法内联

inline只是建议,最终由编译器决定;与宏的区别(无宏的缺点)

⭐⭐⭐

构造函数

名称与类相同,无返回类型,用于对象初始化;支持默认参数和重载

初始化列表(initialization list) vs 函数体内赋值(效率差异)

⭐⭐⭐⭐

访问级别(access level)

public成员可被外部访问,private成员仅限类内部使用;数据应封装为private

直接访问private数据会导致编译错误,需通过public函数间接操作

⭐⭐

函数重载(overloading)

同名函数通过参数类型/数量区分,编译器会进行名称修饰(name mangling)

默认参数可能导致重载冲突(如无参构造函数与带默认参数的构造函数)

⭐⭐⭐

析构函数

名称加~,用于释放资源;不带指针的类通常无需显式定义

带指针的类需自定义析构函数(后续字符串例子会涉及)

⭐⭐

初始化列表(initialization list)

构造函数特有语法,直接初始化成员变量(效率高于函数体内赋值)

初始化阶段(冒号后)与赋值阶段(大括号内)的差异

⭐⭐⭐⭐