- C++
C++ 面向对象编程
- 2025-5-29 15:56:42 @
C++ 面向对象编程完整教程
1. 面向对象编程基础
什么是面向对象编程(OOP)?
- 将数据和操作数据的函数捆绑在一起(封装)
- 通过抽象、继承和多态实现代码复用和灵活性
- 模拟现实世界的对象关系
OOP四大特性:
- 封装(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
- 抽象(Abstraction)
2. 类与对象
类(Class):用户自定义的数据类型,包含数据成员和成员函数。
对象(Object):类的实例。
示例:
#include <iostream>
#include <string>
// 定义类
class Person {
private:
// 私有数据成员
std::string name;
int age;
public:
// 构造函数
Person(std::string n, int a) {
name = n;
age = a;
}
// 成员函数
void introduce() {
std::cout << "我叫" << name << ",今年" << age << "岁。" << std::endl;
}
// Getter和Setter
int getAge() const {
return age;
}
void setAge(int a) {
if (a > 0) age = a; // 数据验证
}
};
int main() {
// 创建对象
Person p1("张三", 25);
Person p2("李四", 30);
// 调用成员函数
p1.introduce(); // 输出: 我叫张三,今年25岁。
p2.introduce(); // 输出: 我叫李四,今年30岁。
// 修改年龄
p1.setAge(26);
std::cout << "修改后张三的年龄: " << p1.getAge() << std::endl;
return 0;
}
3. 访问控制
访问修饰符:
private
:只能被类内部访问public
:可以被任何外部代码访问protected
:可以被类内部和子类访问
示例:
class BankAccount {
private:
double balance; // 私有成员,外部无法直接访问
public:
// 公有接口
void deposit(double amount) {
if (amount > 0) balance += amount;
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
double getBalance() const {
return balance;
}
};
4. 构造函数与析构函数
构造函数(Constructor):
- 与类同名,无返回类型
- 创建对象时自动调用
- 可以重载
析构函数(Destructor):
- 与类同名,前面加
~
- 对象销毁时自动调用
- 不接受参数,不能重载
示例:
class Resource {
private:
int* data;
public:
// 默认构造函数
Resource() {
data = new int[100]; // 分配资源
std::cout << "资源已分配" << std::endl;
}
// 带参数的构造函数
Resource(int size) {
data = new int[size];
std::cout << "分配了大小为" << size << "的资源" << std::endl;
}
// 析构函数
~Resource() {
delete[] data; // 释放资源
std::cout << "资源已释放" << std::endl;
}
};
int main() {
{
Resource r1; // 调用默认构造函数
Resource r2(200); // 调用带参数的构造函数
} // r1和r2超出作用域,自动调用析构函数
return 0;
}
5. 继承
继承:允许一个类(子类)继承另一个类(父类)的属性和方法。
语法:
class 子类 : 访问修饰符 父类 {
// 子类成员
};
示例:
// 基类
class Animal {
protected:
std::string name;
public:
Animal(std::string n) : name(n) {}
void eat() {
std::cout << name << "正在吃东西" << std::endl;
}
virtual void makeSound() { // 虚函数
std::cout << name << "发出声音" << std::endl;
}
};
// 派生类
class Dog : public Animal {
public:
Dog(std::string n) : Animal(n) {}
void makeSound() override { // 重写虚函数
std::cout << name << "汪汪叫" << std::endl;
}
void fetch() {
std::cout << name << "正在捡球" << std::endl;
}
};
// 派生类
class Cat : public Animal {
public:
Cat(std::string n) : Animal(n) {}
void makeSound() override { // 重写虚函数
std::cout << name << "喵喵叫" << std::endl;
}
};
int main() {
Dog dog("小白");
Cat cat("小花");
dog.eat(); // 输出: 小白正在吃东西
dog.makeSound(); // 输出: 小白汪汪叫
dog.fetch(); // 输出: 小白正在捡球
cat.eat(); // 输出: 小花正在吃东西
cat.makeSound(); // 输出: 小花喵喵叫
return 0;
}
6. 多态
多态:通过基类指针或引用调用派生类的重写函数。
实现条件:
- 基类中使用
virtual
关键字声明虚函数 - 派生类中使用
override
关键字重写虚函数
示例:
int main() {
Animal* animal1 = new Dog("小白");
Animal* animal2 = new Cat("小花");
animal1->makeSound(); // 输出: 小白汪汪叫
animal2->makeSound(); // 输出: 小花喵喵叫
delete animal1;
delete animal2;
return 0;
}
7. 抽象类与纯虚函数
纯虚函数:在基类中声明但没有实现的虚函数。
抽象类:包含至少一个纯虚函数的类,不能实例化。
示例:
// 抽象类
class Shape {
public:
// 纯虚函数
virtual double area() const = 0;
// 普通虚函数
virtual void draw() const {
std::cout << "绘制形状" << std::endl;
}
};
// 派生类
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
void draw() const override {
std::cout << "绘制圆形" << std::endl;
}
};
int main() {
// Shape s; // 错误!不能实例化抽象类
Shape* circle = new Circle(5.0);
std::cout << "圆的面积: " << circle->area() << std::endl; // 输出: 78.5397
circle->draw(); // 输出: 绘制圆形
delete circle;
return 0;
}
8. 运算符重载
运算符重载:允许自定义运算符对类对象的行为。
示例:重载+
运算符实现复数加法
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载+运算符
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 重载<<运算符(友元函数)
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real;
if (c.imag >= 0) os << "+";
os << c.imag << "i";
return os;
}
};
int main() {
Complex c1(3, 4);
Complex c2(1, -2);
Complex c3 = c1 + c2; // 调用重载的+运算符
std::cout << "c1 = " << c1 << std::endl; // 输出: c1 = 3+4i
std::cout << "c2 = " << c2 << std::endl; // 输出: c2 = 1-2i
std::cout << "c1 + c2 = " << c3 << std::endl; // 输出: c1 + c2 = 4+2i
return 0;
}
9. 拷贝构造函数与赋值运算符
拷贝构造函数:创建新对象时使用另一个对象初始化。
赋值运算符:将一个对象的值赋给另一个已存在的对象。
示例:
class MyClass {
private:
int* data;
int size;
public:
// 构造函数
MyClass(int s) : size(s) {
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = i;
}
}
// 拷贝构造函数
MyClass(const MyClass& other) : size(other.size) {
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
// 赋值运算符
MyClass& operator=(const MyClass& other) {
if (this != &other) { // 防止自我赋值
delete[] data; // 释放原有资源
size = other.size;
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
return *this;
}
// 析构函数
~MyClass() {
delete[] data;
}
};
10. 智能指针与RAII
RAII(资源获取即初始化):利用对象生命周期管理资源。
智能指针:自动管理动态内存的对象。
示例:
#include <memory>
class Resource {
public:
Resource() { std::cout << "资源分配" << std::endl; }
~Resource() { std::cout << "资源释放" << std::endl; }
void use() { std::cout << "使用资源" << std::endl; }
};
int main() {
// 使用unique_ptr管理资源
{
std::unique_ptr<Resource> res = std::make_unique<Resource>();
res->use();
} // 离开作用域时自动释放资源
// 使用shared_ptr共享资源
{
std::shared_ptr<Resource> res1 = std::make_shared<Resource>();
{
std::shared_ptr<Resource> res2 = res1; // 引用计数+1
res2->use();
} // res2销毁,引用计数-1
res1->use();
} // res1销毁,引用计数为0,释放资源
return 0;
}
11. 面向对象设计原则
SOLID原则:
- 单一职责原则(SRP):一个类只负责一项职责
- 开闭原则(OCP):对扩展开放,对修改关闭
- 里氏替换原则(LSP):子类可以替换父类而不影响程序
- 接口隔离原则(ISP):客户端不应该依赖它不需要的接口
- 依赖倒置原则(DIP):高层模块不依赖低层模块,二者都依赖抽象
设计模式:
- 单例模式(Singleton)
- 工厂模式(Factory)
- 观察者模式(Observer)
- 装饰器模式(Decorator)等
12. 综合示例:银行账户系统
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 抽象基类:账户
class Account {
protected:
std::string accountNumber;
double balance;
public:
Account(std::string number, double initialBalance)
: accountNumber(number), balance(initialBalance) {}
// 纯虚函数:计算利息
virtual double calculateInterest() = 0;
// 存款
void deposit(double amount) {
if (amount > 0) {
balance += amount;
std::cout << "存款成功,当前余额: " << balance << std::endl;
}
}
// 取款
virtual bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
std::cout << "取款成功,当前余额: " << balance << std::endl;
return true;
}
std::cout << "取款失败,余额不足" << std::endl;
return false;
}
// 获取账户信息
virtual void displayInfo() const {
std::cout << "账户号: " << accountNumber << ", 余额: " << balance << std::endl;
}
virtual ~Account() {}
};
// 储蓄账户
class SavingsAccount : public Account {
private:
double interestRate;
public:
SavingsAccount(std::string number, double initialBalance, double rate)
: Account(number, initialBalance), interestRate(rate) {}
double calculateInterest() override {
return balance * interestRate;
}
void displayInfo() const override {
Account::displayInfo();
std::cout << "储蓄账户,利率: " << interestRate << std::endl;
}
};
// 支票账户
class CheckingAccount : public Account {
private:
double overdraftLimit;
public:
CheckingAccount(std::string number, double initialBalance, double limit)
: Account(number, initialBalance), overdraftLimit(limit) {}
double calculateInterest() override {
return 0; // 支票账户通常没有利息
}
bool withdraw(double amount) override {
if (amount > 0 && amount <= (balance + overdraftLimit)) {
balance -= amount;
std::cout << "取款成功,当前余额: " << balance << std::endl;
return true;
}
std::cout << "取款失败,超出透支限额" << std::endl;
return false;
}
void displayInfo() const override {
Account::displayInfo();
std::cout << "支票账户,透支限额: " << overdraftLimit << std::endl;
}
};
// 银行类
class Bank {
private:
std::string name;
std::vector<std::shared_ptr<Account>> accounts;
public:
Bank(std::string bankName) : name(bankName) {}
// 添加账户
void addAccount(std::shared_ptr<Account> account) {
accounts.push_back(account);
std::cout << "账户添加成功" << std::endl;
}
// 显示所有账户信息
void displayAllAccounts() const {
std::cout << "银行名称: " << name << std::endl;
std::cout << "所有账户信息:" << std::endl;
for (const auto& account : accounts) {
account->displayInfo();
std::cout << "利息: " << account->calculateInterest() << std::endl;
std::cout << "------------------------" << std::endl;
}
}
};
int main() {
// 创建银行
Bank bank("ABC银行");
// 创建账户
auto savings = std::make_shared<SavingsAccount>("S1001", 1000.0, 0.03);
auto checking = std::make_shared<CheckingAccount>("C2001", 2000.0, 500.0);
// 添加账户到银行
bank.addAccount(savings);
bank.addAccount(checking);
// 进行交易
savings->deposit(500.0);
checking->withdraw(2300.0);
// 显示所有账户信息
bank.displayAllAccounts();
return 0;
}
总结
面向对象编程核心概念:
- 类与对象:封装数据和行为
- 继承:实现代码复用和层次结构
- 多态:通过虚函数实现运行时绑定
- 抽象:定义接口而不实现具体细节
- 内存管理:智能指针和RAII
最佳实践:
- 优先使用组合而非继承
- 依赖接口而非实现
- 遵循SOLID设计原则
- 使用智能指针避免内存泄漏
通过掌握面向对象编程,你可以设计出更模块化、可维护和可扩展的C++程序。
1 条评论
-
admin SU @ 2025-5-29 15:58:40
🧱 C++ 面向对象编程(OOP)完整教程
📘 什么是面向对象编程?
面向对象编程(Object-Oriented Programming, OOP) 是一种以“对象”为中心的编程范式,强调将数据和操作封装在一起。C++ 支持四大核心特性:
- 封装(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
- 抽象(Abstraction)
🧩 1. 类与对象(Class & Object)
📦 类(Class)
类是对象的模板或蓝图,定义了对象的属性和行为。
// 定义一个简单的类 class Car { private: std::string color; // 私有成员变量 int speed; public: // 构造函数(初始化) Car(std::string c, int s) : color(c), speed(s) {} // 成员函数(方法) void accelerate(int increment) { speed += increment; std::cout << "加速后速度: " << speed << " km/h\n"; } void showInfo() { std::cout << "颜色: " << color << ", 当前速度: " << speed << " km/h\n"; } };
🧍 对象(Object)
对象是类的一个实例。
int main() { Car myCar("红色", 60); // 创建对象 myCar.showInfo(); // 输出信息 myCar.accelerate(20); // 加速 return 0; }
📌 输出示例:
颜色: 红色, 当前速度: 60 km/h 加速后速度: 80 km/h
🔒 2. 封装(Encapsulation)
封装就是把数据设为私有(
private
),并通过公有方法访问它们。示例:使用 getter 和 setter
class Person { private: std::string name; int age; public: // 设置名字 void setName(std::string n) { name = n; } // 获取名字 std::string getName() { return name; } // 设置年龄(带验证) void setAge(int a) { if (a > 0) age = a; } int getAge() { return age; } };
int main() { Person p; p.setName("张三"); p.setAge(25); std::cout << p.getName() << " 的年龄是 " << p.getAge() << " 岁。\n"; return 0; }
📌 输出示例:
张三 的年龄是 25 岁。
🧬 3. 继承(Inheritance)
继承允许我们基于一个已有的类创建新类,称为派生类(子类)。
示例:基类 Animal 和派生类 Dog
#include <iostream> using namespace std; class Animal { public: void eat() { cout << "动物在吃东西。\n"; } }; // 派生类 Dog 继承自 Animal class Dog : public Animal { public: void bark() { cout << "狗在汪汪叫!\n"; } };
int main() { Dog myDog; myDog.eat(); // 来自父类 myDog.bark(); // 子类自己的方法 return 0; }
📌 输出示例:
动物在吃东西。 狗在汪汪叫!
🎭 4. 多态(Polymorphism)
多态是指同一个接口可以有不同的实现方式。通常通过虚函数(
virtual
)实现。示例:基类 Shape 与派生类 Circle、Rectangle
#include <iostream> using namespace std; class Shape { public: virtual void draw() = 0; // 纯虚函数,使 Shape 成为抽象类 }; class Circle : public Shape { public: void draw() override { cout << "画一个圆形 ✅\n"; } }; class Rectangle : public Shape { public: void draw() override { cout << "画一个矩形 🔲\n"; } };
int main() { Shape* shapes[2]; shapes[0] = new Circle(); shapes[1] = new Rectangle(); for (int i = 0; i < 2; ++i) shapes[i]->draw(); delete shapes[0]; delete shapes[1]; return 0; }
📌 输出示例:
画一个圆形 ✅ 画一个矩形 🔲
🧠 5. 抽象(Abstraction)
抽象隐藏复杂的实现细节,只展示必要的接口。
class BankAccount { private: double balance; public: BankAccount(double initial) : balance(initial) {} void deposit(double amount) { if (amount > 0) balance += amount; } void withdraw(double amount) { if (amount > 0 && amount <= balance) balance -= amount; } double getBalance() const { return balance; } };
int main() { BankAccount acc(1000); acc.deposit(500); acc.withdraw(200); cout << "账户余额: $" << acc.getBalance() << endl; return 0; }
📌 输出示例:
账户余额: $1300
📚 6. 构造函数与析构函数
构造函数:对象创建时自动调用
析构函数:对象销毁时自动调用
class MyClass { public: MyClass() { cout << "构造函数被调用!🔥\n"; } ~MyClass() { cout << "析构函数被调用!💥\n"; } };
int main() { MyClass obj; // 构造函数调用 return 0; // 析构函数调用 }
📌 输出示例:
构造函数被调用!🔥 析构函数被调用!💥
🔄 7. 运算符重载(Operator Overloading)
允许你为运算符赋予新的含义。
class Complex { private: double real, imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 重载 + 运算符 Complex operator+(const Complex& other) { return Complex(real + other.real, imag + other.imag); } void print() { cout << real << " + " << imag << "i" << endl; } };
int main() { Complex c1(3, 4), c2(1, 2); Complex c3 = c1 + c2; c3.print(); // 输出:4 + 6i return 0; }
📌 总结图解
特性 描述 封装 数据私有化,提供公共方法访问 继承 子类继承父类的属性和方法 多态 同一接口,不同实现 抽象 隐藏复杂细节,只暴露必要接口
🧠 学习建议
✅ 先掌握类与对象的基本语法
✅ 熟悉封装和访问控制(private
,protected
,public
)
✅ 掌握继承机制和虚函数实现多态
✅ 使用抽象类设计良好的程序结构
📚 参考资料推荐
- 《C++ Primer》——Stanley B. Lippman
- 《Effective C++》——Scott Meyers
- 《C++面向对象程序设计》——谭浩强
- CppReference.com
🧰 工具推荐
- 编译器:GCC / Clang / MSVC
- IDE:Visual Studio / CLion / Code::Blocks
- 调试工具:GDB / Visual Studio Debugger
- 1