C++ 面向对象核心特性(封装、继承、多态)速览
一、核心概念定义
1. 封装(Encapsulation)
定义:将数据(成员变量)和操作数据的方法(成员函数)捆绑在一个类中,并隐藏内部实现细节,只对外暴露有限的接口。核心目的是数据安全和代码复用,通过访问权限(public/private/protected)控制外部对类内部的访问。
2. 继承(Inheritance)
定义:让一个类(子类/派生类)复用另一个类(父类/基类)的属性和方法,同时可以扩展或重写父类的功能。核心目的是代码复用和层次化设计,C++支持单继承、多继承,且可通过访问控制符控制继承权限。
3. 多态(Polymorphism)
定义:同一行为(函数调用)作用于不同对象时,产生不同的执行结果。C++多态分为两类:
- 静态多态(编译期多态):编译阶段确定调用哪个函数,如函数重载、运算符重载。
- 动态多态(运行期多态):运行阶段确定调用哪个函数,基于虚函数(virtual)实现,核心是“父类指针/引用指向子类对象”。
二、基础细节补充(先理清核心前提)
1. struct与class的核心区别
| 特性 | struct | class |
|---|---|---|
| 默认访问权限 | 成员默认public | 成员默认private |
| 默认继承权限 | 继承默认public | 继承默认private |
| 其他特性 | 可定义类、继承、多态,与class一致 | 可定义类、继承、多态,与struct一致 |
demo验证:
#include <iostream>
using namespace std;
// struct默认public
struct S {
int a; // 默认public
void func() { cout << "S::func" << endl; }
};
// class默认private
class C {
int a; // 默认private
void func() { cout << "C::func" << endl; }
};
// 继承权限验证
struct SChild : S {}; // public继承,可访问S的a和func
class CChild : C {}; // private继承,不可访问C的a和func
int main() {
S s;
s.a = 10; // 正常访问(public)
s.func();
C c;
// c.a = 10; // 编译报错(private)
// c.func(); // 编译报错(private)
return 0;
}
2. 对象的创建方式 & new关键字的区别
C++中对象有3种创建方式,核心区别是内存分配位置和生命周期:
| 创建方式 | 语法示例 | 内存位置 | 生命周期 | new有无区别 |
|---|---|---|---|---|
| 栈上创建 | A obj; |
栈 | 超出作用域自动销毁 | 无new,无需手动释放,效率高 |
| 堆上创建 | A* obj = new A(); |
堆 | 需手动delete销毁 | 有new,需手动释放,内存空间更大 |
| 全局/静态对象 | static A obj; |
全局/静态区 | 程序结束时销毁 | 无需new,生命周期贯穿整个程序 |
demo验证:
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A构造" << endl; }
~A() { cout << "A析构" << endl; }
};
// 全局对象
A globalA;
void test() {
// 栈对象:函数结束自动析构
A stackA;
// 堆对象:需手动delete
A* heapA = new A();
delete heapA; // 注释此行会导致内存泄漏
}
int main() {
cout << "进入main" << endl;
test();
// 静态对象:main结束后析构
static A staticA;
cout << "退出main" << endl;
return 0;
}
/* 输出顺序(关键看析构时机):
A构造(全局对象)
进入main
A构造(栈对象)
A构造(堆对象)
A析构(堆对象)
A析构(栈对象)
退出main
A析构(静态对象)
A析构(全局对象)
*/
三、继承的详细讲解 & 最小demo
1. 继承的基本语法与访问权限
继承权限(public/protected/private)决定子类对父类成员的访问权限,核心规则:
- public继承:父类public→子类public,父类protected→子类protected,父类private→子类不可访问。
- protected继承:父类public/protected→子类protected,父类private→不可访问。
- private继承:父类public/protected→子类private,父类private→不可访问。
demo(public继承,最常用):
#include <iostream>
using namespace std;
// 父类
class Parent {
public:
int pub;
protected:
int pro;
private:
int pri;
public:
Parent() : pub(1), pro(2), pri(3) {}
void showPri() { cout << "Parent::pri = " << pri << endl; }
};
// 子类(public继承)
class Child : public Parent {
public:
void show() {
cout << "pub = " << pub << endl; // 可访问(public)
cout << "pro = " << pro << endl; // 可访问(protected)
// cout << "pri = " << pri << endl; // 编译报错(不可访问)
showPri(); // 可通过父类public方法访问private成员
}
};
int main() {
Child c;
c.show();
c.pub = 10; // 外部可访问子类public成员
// c.pro = 20; // 编译报错(protected,外部不可访问)
return 0;
}
2. 多继承(C++特有)
定义:一个子类继承多个父类,语法class Child : public P1, public P2 {}。
注意:多继承可能导致“菱形继承”(子类继承的两个父类都继承自同一个基类),需用virtual虚继承解决。
demo(基础多继承 + 菱形继承解决):
#include <iostream>
using namespace std;
// 菱形继承顶层父类
class Top {
public:
int a = 10;
};
// 中间父类1(虚继承Top)
class Mid1 : virtual public Top {};
// 中间父类2(虚继承Top)
class Mid2 : virtual public Top {};
// 子类(多继承Mid1、Mid2)
class Child : public Mid1, public Mid2 {};
int main() {
Child c;
// 无虚继承时会报错:a的定义不明确(Mid1和Mid2各有一个a)
c.a = 20;
cout << c.a << endl; // 输出20,虚继承解决了数据冗余
return 0;
}
3. 子类&父类构造/析构的执行时机
核心规则:
- 构造顺序:父类构造 → 子类构造(若有多个父类,按继承顺序构造)。
- 析构顺序:子类析构 → 父类析构(与构造相反)。
demo验证:
#include <iostream>
using namespace std;
class P1 {
public:
P1() { cout << "P1构造" << endl; }
~P1() { cout << "P1析构" << endl; }
};
class P2 {
public:
P2() { cout << "P2构造" << endl; }
~P2() { cout << "P2析构" << endl; }
};
// 继承顺序:P1 → P2
class Child : public P1, public P2 {
public:
Child() { cout << "Child构造" << endl; }
~Child() { cout << "Child析构" << endl; }
};
int main() {
Child c;
/* 输出顺序:
P1构造
P2构造
Child构造
Child析构
P2析构
P1析构
*/
return 0;
}
4. 友元(friend):突破封装的特殊机制
定义:友元函数/友元类可以访问类的private/protected成员,但友元关系不继承(子类的友元不能访问父类的私有成员)。
demo(友元类):
#include <iostream>
using namespace std;
class Parent {
private:
int secret = 100;
// 声明FriendClass为友元类
friend class FriendClass;
};
class FriendClass {
public:
void showSecret(Parent& p) {
// 友元类可访问Parent的private成员
cout << "Parent::secret = " << p.secret << endl;
}
};
// 子类继承Parent,但FriendClass不能访问子类新增的私有成员
class Child : public Parent {
private:
int childSecret = 200;
};
int main() {
Parent p;
FriendClass f;
f.showSecret(p); // 输出100
Child c;
// f.showSecret(c); // 可调用,但FriendClass仍只能访问Parent的secret,无法访问childSecret
return 0;
}
四、多态的详细讲解 & 最小demo
1. 静态多态(编译期多态)
(1)函数重载(同一作用域,同名不同参数)
demo:
#include <iostream>
using namespace std;
class A {
public:
// 函数重载:参数个数/类型不同
void func(int a) { cout << "func(int) = " << a << endl; }
void func(int a, int b) { cout << "func(int,int) = " << a + b << endl; }
void func(string s) { cout << "func(string) = " << s << endl; }
};
int main() {
A a;
a.func(10); // 调用func(int)
a.func(10, 20); // 调用func(int,int)
a.func("hello"); // 调用func(string)
return 0;
}
(2)运算符重载(自定义运算符行为)
demo(重载+号):
#include <iostream>
using namespace std;
class Point {
public:
int x, y;
Point(int x=0, int y=0) : x(x), y(y) {}
// 重载+号:成员函数形式
Point operator+(const Point& other) {
return Point(x + other.x, y + other.y);
}
};
int main() {
Point p1(1,2), p2(3,4);
Point p3 = p1 + p2; // 等价于p1.operator+(p2)
cout << "p3.x = " << p3.x << ", p3.y = " << p3.y << endl; // 输出4,6
return 0;
}
2. 动态多态(运行期多态)
核心是虚函数(virtual),必须满足两个条件:
- 父类声明虚函数,子类重写(override)该函数。
- 通过父类指针/引用指向子类对象,调用虚函数。
(1)基础虚函数demo
#include <iostream>
using namespace std;
// 父类
class Animal {
public:
// 虚函数
virtual void speak() {
cout << "动物叫" << endl;
}
// 虚析构:防止子类析构函数不执行(内存泄漏)
virtual ~Animal() {
cout << "Animal析构" << endl;
}
};
// 子类1
class Cat : public Animal {
public:
// 重写父类虚函数(override可选,建议加,编译器检查)
void speak() override {
cout << "猫叫:喵" << endl;
}
~Cat() override {
cout << "Cat析构" << endl;
}
};
// 子类2
class Dog : public Animal {
public:
void speak() override {
cout << "狗叫:汪" << endl;
}
~Dog() override {
cout << "Dog析构" << endl;
}
};
int main() {
// 父类指针指向子类对象
Animal* a1 = new Cat();
Animal* a2 = new Dog();
a1->speak(); // 输出“猫叫:喵”(运行期确定)
a2->speak(); // 输出“狗叫:汪”(运行期确定)
delete a1; // 若无虚析构,仅执行Animal析构,有虚析构则先Cat后Animal
delete a2;
return 0;
}
(2)纯虚函数 & 抽象类
纯虚函数:virtual 返回值 函数名() = 0;,无函数体。
抽象类:包含纯虚函数的类,不能实例化,只能作为父类被继承(子类必须重写纯虚函数,否则子类也是抽象类)。
demo:
#include <iostream>
using namespace std;
// 抽象类(包含纯虚函数)
class Shape {
public:
// 纯虚函数:计算面积
virtual double getArea() = 0;
virtual ~Shape() = default;
};
// 子类1:矩形
class Rectangle : public Shape {
private:
double w, h;
public:
Rectangle(double w, double h) : w(w), h(h) {}
// 必须重写纯虚函数
double getArea() override {
return w * h;
}
};
// 子类2:圆形
class Circle : public Shape {
private:
double r;
public:
Circle(double r) : r(r) {}
double getArea() override {
return 3.14 * r * r;
}
};
int main() {
// Shape s; // 编译报错:抽象类不能实例化
Shape* s1 = new Rectangle(2, 3);
Shape* s2 = new Circle(2);
cout << "矩形面积:" << s1->getArea() << endl; // 6
cout << "圆形面积:" << s2->getArea() << endl; // 12.56
delete s1;
delete s2;
return 0;
}
五、基于继承&多态的设计模式(附代码示例)
设计模式是面向对象思想的最佳实践,以下是最常用的3种基于继承/多态的模式:
1. 工厂方法模式(创建型)
应用场景:需要统一创建不同类型的对象,隐藏对象创建的细节(如日志工厂、数据库连接工厂)。
核心思想:定义一个创建对象的接口(抽象工厂),让子类决定创建哪种产品对象。
代码示例(日志工厂):
#include <iostream>
#include <string>
using namespace std;
// 产品抽象类:日志
class Logger {
public:
virtual void log(const string& msg) = 0;
virtual ~Logger() = default;
};
// 具体产品1:控制台日志
class ConsoleLogger : public Logger {
public:
void log(const string& msg) override {
cout << "[控制台日志] " << msg << endl;
}
};
// 具体产品2:文件日志
class FileLogger : public Logger {
public:
void log(const string& msg) override {
cout << "[文件日志] " << msg << endl; // 实际开发中写入文件
}
};
// 工厂抽象类
class LoggerFactory {
public:
virtual Logger* createLogger() = 0;
virtual ~LoggerFactory() = default;
};
// 具体工厂1:控制台日志工厂
class ConsoleLoggerFactory : public LoggerFactory {
public:
Logger* createLogger() override {
return new ConsoleLogger();
}
};
// 具体工厂2:文件日志工厂
class FileLoggerFactory : public LoggerFactory {
public:
Logger* createLogger() override {
return new FileLogger();
}
};
// 客户端代码
int main() {
// 切换日志类型只需修改工厂,无需修改业务逻辑
LoggerFactory* factory = new ConsoleLoggerFactory();
// LoggerFactory* factory = new FileLoggerFactory();
Logger* logger = factory->createLogger();
logger->log("系统启动成功");
delete logger;
delete factory;
return 0;
}
2. 策略模式(行为型)
应用场景:同一类问题有多种解决策略,需动态切换策略(如支付方式、排序算法)。
核心思想:将不同策略封装为独立类,通过多态动态调用不同策略的方法。
代码示例(支付策略):
#include <iostream>
#include <string>
using namespace std;
// 策略抽象类:支付方式
class PaymentStrategy {
public:
virtual void pay(double amount) = 0;
virtual ~PaymentStrategy() = default;
};
// 具体策略1:支付宝支付
class AliPay : public PaymentStrategy {
public:
void pay(double amount) override {
cout << "使用支付宝支付:" << amount << "元" << endl;
}
};
// 具体策略2:微信支付
class WeChatPay : public PaymentStrategy {
public:
void pay(double amount) override {
cout << "使用微信支付:" << amount << "元" << endl;
}
};
// 上下文类:订单(使用策略)
class Order {
private:
PaymentStrategy* strategy;
double amount;
public:
Order(double amount, PaymentStrategy* strategy) : amount(amount), strategy(strategy) {}
void pay() {
strategy->pay(amount);
}
~Order() {
delete strategy;
}
};
// 客户端代码
int main() {
// 动态切换支付策略
Order order1(99.9, new AliPay());
order1.pay(); // 支付宝支付
Order order2(199.9, new WeChatPay());
order2.pay(); // 微信支付
return 0;
}
3. 观察者模式(行为型)
应用场景:一个对象状态变化时,通知多个依赖对象更新(如消息推送、事件监听)。
核心思想:观察者(订阅者)注册到被观察者(发布者),被观察者状态变化时主动通知所有观察者。
代码示例(消息推送):
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 前向声明:观察者抽象类
class Observer;
// 被观察者抽象类:发布者
class Subject {
protected:
vector<Observer*> observers; // 观察者列表
public:
// 注册观察者
void attach(Observer* obs) {
observers.push_back(obs);
}
// 移除观察者
void detach(Observer* obs) {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == obs) {
observers.erase(it);
break;
}
}
}
// 通知所有观察者
virtual void notify(const string& msg) = 0;
virtual ~Subject() = default;
};
// 观察者抽象类:订阅者
class Observer {
public:
virtual void update(const string& msg) = 0;
virtual ~Observer() = default;
};
// 具体被观察者:公众号
class OfficialAccount : public Subject {
private:
string name;
public:
OfficialAccount(string name) : name(name) {}
// 发布文章(状态变化)
void publishArticle(const string& title) {
cout << name << "发布了新文章:《" << title << "》" << endl;
notify(title); // 通知所有订阅者
}
void notify(const string& msg) override {
for (auto obs : observers) {
obs->update(msg);
}
}
};
// 具体观察者:用户
class User : public Observer {
private:
string username;
public:
User(string username) : username(username) {}
void update(const string& msg) override {
cout << username << "收到通知:有新文章《" << msg << "》" << endl;
}
};
// 客户端代码
int main() {
// 创建公众号
OfficialAccount* account = new OfficialAccount("C++编程");
// 创建用户(观察者)
Observer* u1 = new User("张三");
Observer* u2 = new User("李四");
// 订阅
account->attach(u1);
account->attach(u2);
// 发布文章(触发通知)
account->publishArticle("C++多态详解");
// 取消订阅
account->detach(u1);
account->publishArticle("C++设计模式");
delete u1;
delete u2;
delete account;
return 0;
}
六、总结
核心知识点回顾
- 封装:通过
public/private/protected隐藏内部细节,只暴露接口,struct与class的核心区别是默认访问/继承权限。 - 继承:子类复用父类代码,构造顺序为“父→子”,析构相反;多继承需注意菱形继承,用虚继承解决;友元关系不继承。
- 多态:静态多态(编译期,函数/运算符重载),动态多态(运行期,虚函数/纯虚函数),虚析构是避免子类内存泄漏的关键。
- 设计模式:工厂方法封装对象创建,策略模式封装算法/行为,观察者模式实现对象间的消息通知,均基于继承+多态实现“开闭原则”(对扩展开放,对修改关闭)。
关键实践建议
- 优先使用
public继承,避免private/protected继承(可读性差)。 - 动态多态必须用父类指针/引用,且父类析构函数建议声明为
virtual。 - 抽象类(纯虚函数)用于定义接口,强制子类实现核心功能,是设计模式的基础。
- 设计模式的核心是“解耦”,不要过度使用,需结合业务场景选择。

浙公网安备 33010602011771号