C++进阶——类与对象
一、基础概念
- 什么是类?
定义:类是用户自定义的数据类型,是对象的蓝图或模板。
组成:
成员变量(属性):描述对象的特征(如:汽车的品牌、颜色)
成员函数(方法):定义对象的行为(如:汽车启动、加速)
- 什么是对象?
定义:对象是类的实例(Instance),占用内存空间。
类比:
类 → 建筑设计图纸
对象 → 按图纸建造的房子
二、类的定义与使用
- 基本语法
class ClassName {
public: // 访问修饰符(后续详解)
// 成员变量
DataType member1;
DataType member2;
// 成员函数
ReturnType method1(Parameters) { ... }
ReturnType method2(Parameters);
};
// 类外定义成员函数
ReturnType ClassName::method2(Parameters) { ... }
- 示例:汽车类
#include <iostream>
#include <string>
class Car {
public:
// 成员变量
std::string brand;
std::string color;
int speed;
// 成员函数
void accelerate(int increment) {
speed += increment;
}
void displayInfo() {
std::cout << brand << " " << color << ", Speed: " << speed << " km/h\n";
}
};
int main() {
// 创建对象
Car myCar;
myCar.brand = "Toyota";
myCar.color = "Red";
myCar.speed = 0;
// 调用方法
myCar.accelerate(20);
myCar.displayInfo(); // 输出: Toyota Red, Speed: 20 km/h
return 0;
}
三、访问控制
- 访问修饰符
- public:类外可直接访问
- private(默认):仅类内和友元可访问
- protected:类内、派生类、友元可访问
- 封装(Encapsulation)原则
隐藏内部实现,通过公共接口控制访问
- 目的:规范访问
- 示例:
class BankAccount {
private:
double balance; // 私有变量
public:
void deposit(double amount) {
if (amount > 0) balance += amount;
}
double getBalance() {
return balance;
}
};
int main() {
BankAccount account;
account.deposit(1000);
// account.balance = -500; // 错误!无法直接访问私有成员
std::cout << account.getBalance(); // 正确
}
四、构造函数(Constructor)与析构函数(Destructor)
- 构造函数
- 作用:初始化对象(自动调用)
- 特点:
与类同名
无返回类型
可重载(多个构造函数) - 示例:
class Student {
private:
std::string name;
int age;
public:
// 默认构造函数
Student() : name("Unknown"), age(0) {}
// 带参数构造函数
Student(std::string n, int a) : name(n), age(a) {}
void display() {
std::cout << name << ", " << age << " years old\n";
}
};
int main() {
Student s1; // 调用默认构造函数
Student s2("Alice", 20); // 调用带参数构造函数
s2.display(); // Alice, 20 years old
}
- 析构函数
- 作用:清理资源(如释放内存)
- 特点:
名称:~ClassName()
无参数,不可重载 - 示例:
class FileHandler {
public:
FileHandler() { std::cout << "File opened\n"; }
~FileHandler() { std::cout << "File closed\n"; } // 析构函数
};
int main() {
FileHandler f; // 构造时输出
// 析构函数在对象离开作用域时自动调用
}
// 输出:
// File opened
// File closed
五、静态成员
- 静态变量
- 特性:
属于类而非对象
所有对象共享同一份拷贝 - 示例:
class Counter {
public:
static int count; // 声明静态变量
Counter() { count++; }
~Counter() { count--; }
};
int Counter::count = 0; // 定义并初始化
int main() {
Counter c1, c2;//定义c1和c2时都进行了加一操作
std::cout << Counter::count; // 输出 2
}
- 静态函数
- 只能访问静态成员
- 示例:
class MathUtils {
public:
static int square(int x) { return x * x; }
};
int main() {
std::cout << MathUtils::square(5); // 输出 25
}
六、继承(Inheritance)
- 基本语法
class BaseClass { /* ... */ };
// 公有继承
class DerivedClass : public BaseClass { /* ... */ };
- 示例:动物类层次
class Animal {
public:
void eat() { std::cout << "Eating...\n"; }
};
class Dog : public Animal {
public:
void bark() { std::cout << "Woof!\n"; }
};
int main() {
Dog myDog;
myDog.eat(); // 继承自基类
myDog.bark(); // 派生类自有方法
}
七、多态(Polymorphism)
- 虚函数(Virtual Functions)
class Shape {
public:
virtual void draw() { // 虚函数
std::cout << "Drawing a shape\n";
}
};
class Circle : public Shape {
public:
void draw() override { // 重写虚函数
std::cout << "Drawing a circle\n";
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // 输出: Drawing a circle
delete shape;
}
八、练习与巩固
基础练习:
定义一个 Book 类,包含书名、作者、价格属性和显示信息的方法。
- 简单版本代码示例:
#include <iostream>
#include <string>
class Book {
public:
// 成员变量
std::string book_name;
std::string author;
float price;
// 成员函数
void displayInfo() {
std::cout << book_name << " " << author << ", price: " << price << "yuan\n";
}
};
int main() {
// 创建对象
Book mybook;
mybook.book_name = "if give me three days light";
mybook.author = "omb";
mybook.price = 20.5;
// 调用方法
mybook.displayInfo(); // 输出: Toyota Red, Speed: 20 km/h
return 0;
}
- 改进版:
代码评价与改进建议
- 封装性不足
问题:成员变量(book_name, author, price)被声明为 public,外部可以直接修改,破坏了面向对象的封装原则。
改进:将成员变量设为 private,通过公共方法(getter/setter)访问。
- 缺少构造函数
问题:对象创建后需要逐个手动赋值,容易遗漏初始化。
改进:添加构造函数,方便对象初始化。
- 代码规范性
建议:避免 using namespace std;,改为显式使用 std:: 前缀(防止命名冲突)。
改进后的代码:
#include <iostream>
#include <string>
class Book {
private: // 成员变量设为私有,增强封装性
std::string book_name;
std::string author;
double price; // 使用 double 提高精度
public:
// 构造函数(初始化成员变量)
Book(const std::string& name, const std::string& author_name, double book_price)
: book_name(name), author(author_name), price(book_price) {}
// 显示书籍信息(const 表示不修改成员变量)
void displayInfo() const {
std::cout << "Book: " << book_name
<< "\nAuthor: " << author
<< "\nPrice: " << price << " yuan\n";
}
// Getter/Setter 方法(保护数据安全)
void setPrice(double new_price) {
if (new_price >= 0) { // 简单的数据校验
price = new_price;
}
}
double getPrice() const { return price; }
// 可以类似添加其他属性的 getter/setter
};
int main() {
// 使用构造函数初始化对象
Book mybook("If I Had Three Days of Light", "Helen Keller", 20.5);
// 调用方法显示信息
mybook.displayInfo(); // 输出正确的书籍信息
// 修改价格(通过 setter)
mybook.setPrice(25.0);
std::cout << "Updated price: " << mybook.getPrice() << " yuan\n";
return 0;
}
改进点详解
- 封装性
为什么重要:封装是面向对象的核心原则,可以防止外部代码意外修改对象内部状态。
实现方式:
成员变量设为 private
通过 getPrice() 和 setPrice() 方法访问和修改价格
- 构造函数
优势:
- 强制在创建对象时提供完整初始化数据
- 避免对象处于“半初始化”状态
- 使用成员初始化列表(更高效)
语法:
Book(const std::string& name, const std::string& author_name, double book_price)
: book_name(name), author(author_name), price(book_price) {}
- 输出格式修正
修正后的输出示例:
Book: If I Had Three Days of LightAuthor: Helen KellerPrice: 20.5 yuan
- 其他优化
数据类型:price 改为 double(更精确的浮点数)
const 正确性:displayInfo() 和 getPrice() 标记为 const
数据校验:在 setPrice() 中检查价格非负
进阶挑战:
- 实现一个 Stack 类,包含压栈(push)、弹栈(pop)、查看栈顶元素的方法
- 使用私有数组存储数据,确保封装性