一、class声明与定义
基本结构: class声明包含class head和class body两部分,其中body包含成员函数和数据成员
声明与定义关系: 在class body内直接实现的函数既是声明也是定义,如real()和imag()函数;仅有声明无定义的函数需在外部实现,如operator+=
数据封装: 数据成员re和im被声明为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: 仅类内部可访问,如数据成员re和im
protected: 保护成员(本课程未涉及)
2. 封装原则
数据隐藏: 所有数据成员应声明为private
访问控制: 必须通过public成员函数访问私有数据
错误示例: 直接访问c1.re会导致编译错误
3. 使用规范
段落组织: public/private区域可交替出现
函数分类: 外部接口放public,内部辅助函数可放private
friend例外: friend函数突破封装限制,需谨慎使用
五、构造函数
10:03
1. 基本概念与示例
10:21
自动调用机制: 创建对象时自动被调用,无需手动调用。例如创建complex c1(2,1)、complex c2和complex* 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),通常不需要自定义析构函数。
分类原则: 类可分为带指针和不带指针两类,前者通常需要自定义析构函数进行资源释放。