功能描述
本示例程序展示了 C++ 中面向对象编程的核心概念,包括:
- 类的定义和基本结构
- 构造函数和析构函数
- 成员变量和成员方法
- 访问控制(public、private)
- 拷贝构造函数
- 静态成员
- 运算符重载
- 继承与多态
- 虚函数和纯虚函数
- 抽象类
- 组合与聚合
- 移动语义
- 智能指针
代码解析
1. 基本类结构
1 2 3 4 5 6 7 8 9
| class Rectangle { private: double width; double height;
public: };
|
说明:
- 类是一种用户定义的数据类型,包含数据成员(变量)和成员函数(方法)。
private 部分包含只能在类内部访问的成员。
public 部分包含可以在类外部访问的成员。
2. 构造函数和析构函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Rectangle() : width(0), height(0) { std::cout << "默认构造函数被调用" << std::endl; }
Rectangle(double w, double h) : width(w), height(h) { std::cout << "参数化构造函数被调用" << std::endl; }
Rectangle(const Rectangle& other) : width(other.width), height(other.height) { std::cout << "拷贝构造函数被调用" << std::endl; }
~Rectangle() { std::cout << "析构函数被调用" << std::endl; }
|
说明:
- 构造函数在创建对象时被调用,用于初始化对象。
- 默认构造函数没有参数。
- 参数化构造函数接受参数,用于初始化对象的成员变量。
- 拷贝构造函数用于从另一个对象创建新对象。
- 析构函数在对象销毁时被调用,用于清理资源。
3. 成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| double getWidth() const { return width; }
double getHeight() const { return height; }
void setWidth(double w) { width = w; }
void setHeight(double h) { height = h; }
double area() const { return width * height; }
double perimeter() const { return 2 * (width + height); }
void display() const { std::cout << "矩形: " << width << " x " << height << std::endl; std::cout << "面积: " << area() << std::endl; std::cout << "周长: " << perimeter() << std::endl; }
|
说明:
- 成员方法是类的函数,用于操作对象的数据。
const 成员方法不能修改对象的状态。
- getter 方法用于获取私有成员变量的值。
- setter 方法用于设置私有成员变量的值。
- 其他方法用于执行特定的操作,如计算面积和周长。
4. 静态成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class BankAccount { private: std::string accountNumber; std::string accountHolder; double balance; static int accountCount;
public: BankAccount(const std::string& num, const std::string& holder, double initialBalance) : accountNumber(num), accountHolder(holder), balance(initialBalance) { accountCount++; }
static int getAccountCount() { return accountCount; } };
int BankAccount::accountCount = 0;
|
说明:
- 静态成员变量属于类,而不是对象,所有对象共享同一个静态成员变量。
- 静态成员变量必须在类外部初始化。
- 静态成员方法可以在没有对象的情况下调用,只能访问静态成员变量。
5. 运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Point { private: int x; int y;
public: Point(int x = 0, int y = 0) : x(x), y(y) {}
Point operator+(const Point& other) const { return Point(x + other.x, y + other.y); }
Point operator-(const Point& other) const { return Point(x - other.x, y - other.y); }
bool operator==(const Point& other) const { return x == other.x && y == other.y; } };
|
说明:
- 运算符重载允许自定义运算符在类对象上的行为。
- 重载运算符的函数名是
operator 后跟运算符符号。
- 运算符重载函数可以是成员函数或全局函数。
6. 继承与多态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Shape { public: virtual void draw() const { std::cout << "绘制形状" << std::endl; }
virtual double getArea() const { return 0; }
virtual ~Shape() {} };
class Circle : public Shape { private: double radius;
public: Circle(double r) : radius(r) {}
void draw() const override { std::cout << "绘制圆形" << std::endl; }
double getArea() const override { return 3.14159 * radius * radius; } };
|
说明:
- 继承允许一个类(派生类)继承另一个类(基类)的成员。
virtual 关键字用于声明虚函数,支持运行时多态。
override 关键字表示重写基类的虚函数。
- 虚析构函数确保派生类的析构函数被正确调用。
7. 抽象类和纯虚函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Animal { public: virtual void makeSound() const = 0; virtual void eat() const { std::cout << "动物在吃东西" << std::endl; }
virtual ~Animal() {} };
class Dog : public Animal { public: void makeSound() const override { std::cout << "汪汪汪!" << std::endl; } };
|
说明:
- 包含纯虚函数的类是抽象类,不能直接实例化。
- 纯虚函数是没有实现的虚函数,派生类必须提供实现。
- 抽象类用于定义接口,派生类提供具体实现。
8. 组合与聚合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Engine { public: void start() const { std::cout << "引擎启动" << std::endl; } };
class Car { private: Engine engine;
public: void start() const { engine.start(); std::cout << "汽车启动" << std::endl; } };
|
说明:
- 组合是一种”拥有”关系,其中一个类包含另一个类的对象。
- 聚合是一种”使用”关系,其中一个类引用另一个类的对象,但不拥有它。
9. 移动语义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyString { private: char* data;
public: MyString(MyString&& other) noexcept : data(other.data) { other.data = nullptr; std::cout << "移动构造函数被调用" << std::endl; }
MyString& operator=(MyString&& other) noexcept { if (this != &other) { delete[] data; data = other.data; other.data = nullptr; std::cout << "移动赋值运算符被调用" << std::endl; } return *this; } };
|
说明:
- 移动语义允许资源从一个对象转移到另一个对象,避免不必要的复制。
- 移动构造函数和移动赋值运算符接受右值引用(
&&)。
noexcept 表示函数不会抛出异常。
10. 智能指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <memory>
class Person { private: std::string name;
public: Person(const std::string& n) : name(n) { std::cout << "Person " << name << " 被创建" << std::endl; }
~Person() { std::cout << "Person " << name << " 被销毁" << std::endl; }
void sayHello() const { std::cout << "你好,我是 " << name << std::endl; } };
std::unique_ptr<Person> p1 = std::make_unique<Person>("张三"); p1->sayHello();
std::shared_ptr<Person> p2 = std::make_shared<Person>("李四"); std::shared_ptr<Person> p3 = p2;
|
说明:
- 智能指针是管理动态内存的工具,自动处理内存的分配和释放。
std::unique_ptr 拥有独占所有权,不能复制。
std::shared_ptr 共享所有权,使用引用计数。
std::make_unique 和 std::make_shared 是创建智能指针的推荐方式。
编译和运行
在 Windows 上编译(使用 g++):
1
| g++ -std=c++11 -fexec-charset=GBK -o classes classes.cpp
|
运行程序:
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| === 1. 矩形类 === 默认构造函数被调用 矩形: 0 x 0 面积: 0 周长: 0 参数化构造函数被调用 矩形: 5 x 3 面积: 15 周长: 16 拷贝构造函数被调用 矩形: 5 x 3 面积: 15 周长: 16 矩形: 7 x 4 面积: 28 周长: 22 析构函数被调用 析构函数被调用 析构函数被调用
=== 2. 银行账户类 === 账户: 123456 持有人: John Doe 余额: $1000 存入: $500 取出: $200 账户: 123456 持有人: John Doe 余额: $1300 总账户数: 2
=== 3. 点类与运算符重载 === p1: (3, 4) p2: (1, 2) p1 + p2: (4, 6) p1 - p2: (2, 2) p1 == p5: true
=== 4. 继承与多态 === 绘制形状 面积: 0 绘制圆形 面积: 78.5397 绘制矩形 面积: 28
=== 5. 抽象类与接口 === 汪汪汪! 动物在吃东西 喵喵喵! 动物在吃东西
=== 6. 组合与聚合 === 引擎启动 汽车启动
=== 7. 移动语义 === 构造函数被调用 移动构造函数被调用 移动赋值运算符被调用 析构函数被调用 析构函数被调用
=== 8. 智能指针 === Person 张三 被创建 你好,我是 张三 Person 李四 被创建 你好,我是 李四 你好,我是 李四 Person 李四 被销毁 Person 张三 被销毁
|
技术要点
1. 面向对象编程的四大特性
- 封装:将数据和操作数据的方法封装在一个类中,隐藏实现细节。
- 继承:一个类可以继承另一个类的属性和方法,实现代码复用。
- 多态:通过虚函数,不同的对象可以以不同的方式响应相同的消息。
- 抽象:通过抽象类和接口,定义对象的行为而不实现具体细节。
2. 构造函数和析构函数的使用
- 构造函数:用于初始化对象,确保对象在创建时处于有效状态。
- 析构函数:用于清理对象占用的资源,如动态内存、文件句柄等。
- 拷贝构造函数:用于创建一个新对象作为现有对象的副本。
- 移动构造函数:用于将资源从一个对象转移到另一个对象,避免不必要的复制。
3. 访问控制
- public:可以在任何地方访问。
- private:只能在类内部访问。
- protected:可以在类内部和派生类中访问。
4. 虚函数和多态
- 虚函数:在基类中声明,派生类可以重写的函数。
- 纯虚函数:没有实现的虚函数,派生类必须提供实现。
- 抽象类:包含纯虚函数的类,不能直接实例化。
- 多态:通过基类指针或引用调用虚函数时,会根据对象的实际类型调用相应的函数。
5. 运算符重载
- 可以重载大多数 C++ 运算符,如
+、-、*、/、==、!= 等。
- 运算符重载函数可以是成员函数或全局函数。
- 某些运算符必须作为成员函数重载,如
=、[]、()、->。
6. 静态成员
- 静态成员变量:属于类,所有对象共享,必须在类外部初始化。
- 静态成员方法:可以在没有对象的情况下调用,只能访问静态成员变量。
- 静态成员:常用于计数、缓存、工具函数等。
7. 智能指针的使用
- std::unique_ptr:独占所有权,不能复制,只能移动。
- std::shared_ptr:共享所有权,使用引用计数。
- std::weak_ptr:不增加引用计数的 shared_ptr 观察者。
- 智能指针:可以避免内存泄漏,是现代 C++ 中管理动态内存的推荐方式。
8. 移动语义
- 右值引用:使用
&& 表示,指向临时对象。
- 移动构造函数:将资源从一个对象转移到另一个对象。
- 移动赋值运算符:将资源从一个对象转移到另一个已存在的对象。
- 移动语义:可以提高性能,特别是对于大型对象。
9. 组合与继承的选择
- 组合:”拥有”关系,一个类包含另一个类的对象。
- 继承:”是”关系,一个类是另一个类的特殊类型。
- 优先使用组合:组合比继承更灵活,减少了类之间的耦合。
10. 代码组织和最佳实践
- 头文件和源文件分离:类声明放在头文件(.h)中,实现放在源文件(.cpp)中。
- 命名约定:类名使用 PascalCase,成员变量使用 camelCase,常量使用全大写。
- 初始化列表:使用构造函数初始化列表初始化成员变量,而不是在构造函数体中赋值。
- const 正确性:对于不修改对象状态的成员函数,使用
const 修饰。
- 避免使用原始指针:优先使用智能指针管理动态内存。
常见问题
1. 内存泄漏
问题:使用 new 分配内存后,没有使用 delete 释放内存。
解决方案:使用智能指针管理动态内存,或确保每次 new 都有对应的 delete。
2. 构造函数和析构函数的顺序
问题:不了解构造函数和析构函数的调用顺序。
解决方案:
- 构造顺序:基类构造函数 → 成员变量构造函数 → 派生类构造函数。
- 析构顺序:派生类析构函数 → 成员变量析构函数 → 基类析构函数。
3. 虚函数的使用
问题:没有将基类的析构函数声明为虚函数,导致派生类的析构函数不被调用。
解决方案:对于有虚函数的类,将析构函数声明为虚函数。
4. 运算符重载的返回类型
问题:运算符重载函数的返回类型不正确。
解决方案:
- 对于
operator=,返回 *this 的引用。
- 对于
operator+、operator- 等,返回新对象。
5. 静态成员的初始化
问题:静态成员变量没有在类外部初始化。
解决方案:在类外部使用 类型 类名::成员名 = 值; 的形式初始化静态成员变量。
6. 访问控制错误
问题:试图在类外部访问 private 成员。
解决方案:将需要在类外部访问的成员声明为 public,或提供 public 的 getter 和 setter 方法。
7. 继承中的作用域
问题:派生类中的成员与基类中的成员同名,导致基类成员被隐藏。
解决方案:使用 基类名::成员名 访问被隐藏的基类成员,或避免使用同名成员。
8. 智能指针的循环引用
问题:两个对象使用 shared_ptr 相互引用,导致内存泄漏。
解决方案:使用 weak_ptr 打破循环引用。
9. 移动语义的使用
问题:不知道何时使用移动语义,或如何实现移动构造函数。
解决方案:
- 对于包含动态资源的类,实现移动构造函数和移动赋值运算符。
- 使用
std::move() 将左值转换为右值引用。
10. 代码组织
问题:类的声明和实现都放在一个文件中,导致代码难以维护。
解决方案:将类声明放在头文件中,实现放在源文件中,使用包含保护符防止头文件被重复包含。
代码优化建议
使用初始化列表:
- 优先使用构造函数初始化列表初始化成员变量,而不是在构造函数体中赋值。
- 初始化列表可以提高性能,特别是对于大型对象。
使用 const 修饰符:
- 对于不修改对象状态的成员函数,使用
const 修饰。
- 对于不修改参数的函数参数,使用
const 引用。
使用智能指针:
- 优先使用
std::unique_ptr 和 std::shared_ptr 管理动态内存。
- 避免使用原始指针和手动内存管理。
实现移动语义:
- 对于包含动态资源的类,实现移动构造函数和移动赋值运算符。
- 使用
std::move() 优化对象的传递。
使用 override 关键字:
- 在重写基类虚函数时,使用
override 关键字,让编译器检查是否正确重写。
避免使用宏:
- 优先使用
const 变量、枚举和内联函数,而不是宏。
使用命名空间:
- 将相关的类和函数放在一个命名空间中,避免命名冲突。
分离接口和实现:
- 将类声明放在头文件中,实现放在源文件中。
- 使用 Pimpl 手法(指向实现的指针)减少编译依赖。
使用现代 C++ 特性:
- 使用 C++11 及以上的特性,如自动类型推导、范围 for 循环、lambda 表达式等。
- 避免使用过时的特性,如
auto_ptr、bind1st/bind2nd 等。
编写单元测试:
- 为类编写单元测试,确保类的行为符合预期。
- 使用测试框架,如 Google Test、Catch2 等。
总结
C++ 的面向对象编程提供了强大的工具,用于创建模块化、可维护、可扩展的代码:
- 类:封装数据和行为,提供了一种组织代码的方式。
- 继承:实现代码复用,建立类型层次结构。
- 多态:通过虚函数,实现运行时的动态行为。
- 抽象:通过抽象类和接口,定义对象的行为契约。
- 现代 C++ 特性:移动语义、智能指针等,提高代码的性能和安全性。
通过合理使用这些特性,可以创建高质量的 C++ 代码,解决复杂的问题。面向对象编程不仅是一种编程范式,更是一种思维方式,帮助开发者更好地理解和建模现实世界的问题。
classes.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
| #include <iostream> #include <string> #include <memory> #include <vector> #include <cstring>
class Rectangle { private: double width; double height;
public: Rectangle() : width(0), height(0) { std::cout << "默认构造函数被调用" << std::endl; }
Rectangle(double w, double h) : width(w), height(h) { std::cout << "参数化构造函数被调用" << std::endl; }
Rectangle(const Rectangle& other) : width(other.width), height(other.height) { std::cout << "拷贝构造函数被调用" << std::endl; }
~Rectangle() { std::cout << "析构函数被调用" << std::endl; }
double getWidth() const { return width; }
double getHeight() const { return height; }
void setWidth(double w) { width = w; }
void setHeight(double h) { height = h; }
double area() const { return width * height; }
double perimeter() const { return 2 * (width + height); }
void display() const { std::cout << "矩形: " << width << " x " << height << std::endl; std::cout << "面积: " << area() << std::endl; std::cout << "周长: " << perimeter() << std::endl; } };
class BankAccount { private: std::string accountNumber; std::string accountHolder; double balance; static int accountCount;
public: BankAccount(const std::string& num, const std::string& holder, double initialBalance) : accountNumber(num), accountHolder(holder), balance(initialBalance) { accountCount++; }
void deposit(double amount) { if (amount > 0) { balance += amount; std::cout << "存入: $" << amount << std::endl; } }
bool withdraw(double amount) { if (amount > 0 && balance >= amount) { balance -= amount; std::cout << "取出: $" << amount << std::endl; return true; } std::cout << "取款失败" << std::endl; return false; }
double getBalance() const { return balance; }
void display() const { std::cout << "账户: " << accountNumber << std::endl; std::cout << "持有人: " << accountHolder << std::endl; std::cout << "余额: $" << balance << std::endl; }
static int getAccountCount() { return accountCount; } };
int BankAccount::accountCount = 0;
class Point { private: int x; int y;
public: Point(int x = 0, int y = 0) : x(x), y(y) {}
Point operator+(const Point& other) const { return Point(x + other.x, y + other.y); }
Point operator-(const Point& other) const { return Point(x - other.x, y - other.y); }
bool operator==(const Point& other) const { return x == other.x && y == other.y; }
void display() const { std::cout << "(" << x << ", " << y << ")" << std::endl; } };
class Shape { public: virtual void draw() const { std::cout << "绘制形状" << std::endl; }
virtual double getArea() const { return 0; }
virtual ~Shape() {} };
class Circle : public Shape { private: double radius;
public: Circle(double r) : radius(r) {}
void draw() const override { std::cout << "绘制圆形" << std::endl; }
double getArea() const override { return 3.14159 * radius * radius; } };
class RectangleShape : public Shape { private: double width; double height;
public: RectangleShape(double w, double h) : width(w), height(h) {}
void draw() const override { std::cout << "绘制矩形" << std::endl; }
double getArea() const override { return width * height; } };
class Animal { public: virtual void makeSound() const = 0;
virtual void eat() const { std::cout << "动物在吃东西" << std::endl; }
virtual ~Animal() {} };
class Dog : public Animal { public: void makeSound() const override { std::cout << "汪汪汪!" << std::endl; } };
class Cat : public Animal { public: void makeSound() const override { std::cout << "喵喵喵!" << std::endl; } };
class Engine { public: void start() const { std::cout << "引擎启动" << std::endl; } };
class Car { private: Engine engine;
public: void start() const { engine.start(); std::cout << "汽车启动" << std::endl; } };
class MyString { private: char* data;
public: MyString(const char* str) { if (str) { data = new char[strlen(str) + 1]; strcpy(data, str); } else { data = nullptr; } std::cout << "构造函数被调用" << std::endl; }
MyString(MyString&& other) noexcept : data(other.data) { other.data = nullptr; std::cout << "移动构造函数被调用" << std::endl; }
MyString& operator=(MyString&& other) noexcept { if (this != &other) { delete[] data; data = other.data; other.data = nullptr; std::cout << "移动赋值运算符被调用" << std::endl; } return *this; }
~MyString() { delete[] data; std::cout << "析构函数被调用" << std::endl; }
const char* getData() const { return data; } };
class Person { private: std::string name;
public: Person(const std::string& n) : name(n) { std::cout << "Person " << name << " 被创建" << std::endl; }
~Person() { std::cout << "Person " << name << " 被销毁" << std::endl; }
void sayHello() const { std::cout << "你好,我是 " << name << std::endl; } };
int main() { std::cout << "=== 1. 矩形类 ===" << std::endl; { Rectangle rect1; rect1.display();
Rectangle rect2(5.0, 3.0); rect2.display();
Rectangle rect3 = rect2; rect3.display();
rect3.setWidth(7.0); rect3.setHeight(4.0); rect3.display(); }
std::cout << "\n=== 2. 银行账户类 ===" << std::endl; { BankAccount acc1("123456", "John Doe", 1000.0); BankAccount acc2("789012", "Jane Smith", 500.0);
acc1.display(); acc1.deposit(500.0); acc1.withdraw(200.0); acc1.display();
std::cout << "总账户数: " << BankAccount::getAccountCount() << std::endl; }
std::cout << "\n=== 3. 点类与运算符重载 ===" << std::endl; { Point p1(3, 4); Point p2(1, 2); Point p3 = p1 + p2; Point p4 = p1 - p2;
std::cout << "p1: "; p1.display(); std::cout << "p2: "; p2.display(); std::cout << "p1 + p2: "; p3.display(); std::cout << "p1 - p2: "; p4.display();
Point p5(3, 4); std::cout << "p1 == p5: " << (p1 == p5 ? "true" : "false") << std::endl; }
std::cout << "\n=== 4. 继承与多态 ===" << std::endl; { Shape* shape1 = new Shape(); Shape* shape2 = new Circle(5.0); Shape* shape3 = new RectangleShape(7.0, 4.0);
shape1->draw(); std::cout << "面积: " << shape1->getArea() << std::endl;
shape2->draw(); std::cout << "面积: " << shape2->getArea() << std::endl;
shape3->draw(); std::cout << "面积: " << shape3->getArea() << std::endl;
delete shape1; delete shape2; delete shape3; }
std::cout << "\n=== 5. 抽象类与接口 ===" << std::endl; { Animal* dog = new Dog(); Animal* cat = new Cat();
dog->makeSound(); dog->eat();
cat->makeSound(); cat->eat();
delete dog; delete cat; }
std::cout << "\n=== 6. 组合与聚合 ===" << std::endl; { Car car; car.start(); }
std::cout << "\n=== 7. 移动语义 ===" << std::endl; { MyString s1("Hello"); MyString s2 = std::move(s1); MyString s3("World"); s3 = std::move(s2); }
std::cout << "\n=== 8. 智能指针 ===" << std::endl; { std::unique_ptr<Person> p1(new Person("张三")); p1->sayHello();
std::shared_ptr<Person> p2 = std::make_shared<Person>("李四"); std::shared_ptr<Person> p3 = p2;
p2->sayHello(); p3->sayHello(); }
return 0; }
|