Loading

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),必须满足两个条件:

  1. 父类声明虚函数,子类重写(override)该函数。
  2. 通过父类指针/引用指向子类对象,调用虚函数。

(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;
}

六、总结

核心知识点回顾

  1. 封装:通过public/private/protected隐藏内部细节,只暴露接口,structclass的核心区别是默认访问/继承权限。
  2. 继承:子类复用父类代码,构造顺序为“父→子”,析构相反;多继承需注意菱形继承,用虚继承解决;友元关系不继承。
  3. 多态:静态多态(编译期,函数/运算符重载),动态多态(运行期,虚函数/纯虚函数),虚析构是避免子类内存泄漏的关键。
  4. 设计模式:工厂方法封装对象创建,策略模式封装算法/行为,观察者模式实现对象间的消息通知,均基于继承+多态实现“开闭原则”(对扩展开放,对修改关闭)。

关键实践建议

  • 优先使用public继承,避免private/protected继承(可读性差)。
  • 动态多态必须用父类指针/引用,且父类析构函数建议声明为virtual
  • 抽象类(纯虚函数)用于定义接口,强制子类实现核心功能,是设计模式的基础。
  • 设计模式的核心是“解耦”,不要过度使用,需结合业务场景选择。
posted @ 2026-01-14 21:30  StarVik  阅读(11)  评论(0)    收藏  举报