[Basics of Classes]CPP Learn Data Day 0
原帖地址:https://www.cnblogs.com/Reisentyan/p/19725010
蒸馏舍友学过的西嘎嘎笔记。
他写的笔记真好,好得我看一眼就能记住这是个什么东西,ai加持下。感觉很快就能学完吧(
一、 封装 (Encapsulation)
核心思想: 隐藏内部实现细节,对外提供安全的访问接口和初始化机制。
- 访问控制:
private:用于保护核心数据(如m_ownerName,m_balance)和内部辅助函数(如isValidAmount),外部无法直接访问。public:暴露给外部的构造函数和操作接口。
- 初始化列表: 构造函数使用冒号
:语法进行成员变量的初始化,支持条件判断(如initialBalance > 0 ? initialBalance : 0),确保对象创建时的状态合法。 - 命名规范(参考代码习惯): 类成员函数常使用小驼峰命名(如
isValidAmount),非类函数使用大驼峰。成员变量常加m_前缀以作区分。
参考代码:
//一段关于封装的c++代码
class BankAccount
{
private:
std::string m_ownerName{ "" };
double m_balance{ 0 };
// 类函数用小驼峰,非类函数用大驼峰
bool isValidAmount(double amount) const {
return amount > 0;
}
public:
//构造函数
BankAccount(std::string name, double initialBalance)
: m_ownerName(name), m_balance(initialBalance > 0 ? initialBalance : 0)
{};
~BankAccount(){}
};
二、 组合 (Composition)
核心思想: 将简单的类对象作为成员变量,拼装成复杂的类("Has-a" 关系)。
- 实现方式: 在
Car类中,将Engine对象和Wheel数组作为私有成员变量(m_myEngine,m_myWheels[4])。 - 任务委托: 复杂对象通过调用内部成员对象的方法来实现功能。例如,
Car::drive()内部调用了Engine::start()和Wheel::roll()。
参考代码:
//这是一段关于组合的代码:
class Engine {
public:
void start()
{
std::cout << "源神启动" << '\n';
}
};
class Wheel {
public:
void roll()
{
std::cout << "转动" << "\n";
}
};
class Car
{
private:
Engine m_myEngine;
Wheel m_myWheels[4];
public:
void drive() {
std::cout << "准备出发...\n";
m_myEngine.start(); // 委托给内部的发动机对象去工作
for (int i = 0; i < 4; ++i) {
m_myWheels[i].roll();
}
std::cout << "汽车行驶中!\n";
}
};
三、 多态 (Polymorphism)
核心思想: 通过基类接口调用派生类的具体实现,实现动态绑定。
- 抽象基类 (
Animal):- 纯虚函数: 声明后加
= 0(如virtual void speak() const = 0;),强制要求派生类必须实现该函数。 - 虚析构函数: 只要类中包含虚函数,析构函数必须声明为
virtual(如virtual ~Animal() = default;),以防止通过基类指针删除派生类对象时发生内存泄漏。
- 纯虚函数: 声明后加
- 派生类 (
Dog,Cat):- 使用
override关键字修饰重写的虚函数,由编译器检查函数签名是否与基类完全一致,提高代码安全性。
- 使用
- 动态绑定与对象切片:
- 引用传递: 函数参数必须使用引用
&(或指针*),如const Animal& animal。 - 避免切片: 如果按值传递,派生类对象会被裁剪为基类对象,丢失原有特性(对象切片)。
- 虚函数表 (V-Table): 传入引用后,程序在运行时通过查阅对象的虚函数表,动态决定调用哪个具体类(如
Cat)的函数。
- 引用传递: 函数参数必须使用引用
参考代码:
//以下为多态相关知识:
class Animal {
public:
//虚析构函数,只要类里有虚函数,析构函数必须写虚函数
virtual ~Animal() = default;
//加上=0,表示是纯虚函数
virtual void speak()const = 0;
};
class Dog :public Animal {
public:
//override:保证在派生类中声明的重载函数,与基类的虚函数有相同的签名;
void speak() const override {
std::cout << "bark" << '\n';
}
};
class Cat :public Animal {
public:
void speak() const override {
std::cout << "mimi" << '\n';
}
};
//参数中的&是很有必要的,如果没有这个参数,就会发生对象切片的特性
//即,将传入的Animal对象裁剪为基础的Animal对象
void makeThemSpeak(const Animal& animal) {
animal.speak();
//这个时候编译器会去查阅传入对象的虚函数表
//如果它是猫,就会调用猫的函数
return;
}
四、 const 关键字的用法图鉴
const 用于声明“只读契约”,出现位置不同,约束对象不同:
- 放在函数最前面(修饰返回值):
- 声明返回的数据是只读的,调用者不能修改该返回值。
- 放在参数列表中(修饰参数):
- 例如
void makeThemSpeak(const Animal& animal)。 - 保证在函数内部绝对不会修改传入的参数对象。
- 例如
- 放在成员函数的圆括号后、大括号前(修饰成员函数):
- 例如
void speak() const override。 - 专属特性: 仅限类的成员函数使用。
- 底层原理: 成员函数被调用时,编译器会隐式传递一个
this指针。尾部const将这个this指针变为只读,保证该函数不会修改类的任何成员变量。 - 独立函数限制: 普通全局函数(如
makeThemSpeak)没有this指针,因此不能在尾部加const,否则编译器会报错。
- 例如

浙公网安备 33010602011771号