首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

VC++ 面向對象實戰:從繼承機制到構造函數協作全解析

     編輯:關於C++

核心概念:類是問題域的抽象建模工具

面向對象編程(OOP)的本質是定義問題域專屬的數據類型。類不僅封裝數據(屬性)與操作(方法),更建立了現實世界實體與計算模型的映射:

  • 接口契約:public 成員函數定義「能做什麼」,隱藏「怎麼做」。
  • 封裝邊界:private 保護不變量,protected 供派生類擴展。
  • 類型擴展:繼承表達「是一種」關係,復用基類實現並添加特化行為。

繼承機制深度剖析

派生類自動包含基類子對象

派生類對象內存佈局:基類部分 + 派生類自有成員。基類子對象由基類構造函數初始化,派生類構造函數通過成員初始化列表指定調用哪個基類構造函數:


class CBox { // 基類:通用箱子
public:
    double m_Length, m_Width, m_Height;
    explicit CBox(double lv=1.0, double wv=1.0, double hv=1.0)
        : m_Length(lv), m_Width(wv), m_Height(hv) {}
};

class CCandyBox : private CBox { // 派生類:糖果盒
public:
    char* m_Contents;
    explicit CCandyBox(const char* str = "Candy")
        : CBox(), // 顯式調用基類默認構造
          m_Contents(new char[strlen(str)+1]) {
        strcpy_s(m_Contents, strlen(str)+1, str);
    }
    // 禁用拷貝,避免淺拷貝雙重釋放
    CCandyBox(const CCandyBox&) = delete;
    CCandyBox& operator=(const CCandyBox&) = delete;
    ~CCandyBox() { delete[] m_Contents; }
};

三種繼承訪問控制對比

繼承方式基類 public 成員在派生類中基類 protected 成員在派生類中基類 private 成員語義
publicpublicprotected不可訪問is-a 關係,對外暴露基類接口
protectedprotectedprotected不可訪問僅供進一步派生類使用
private (默認)privateprivate不可訪問implemented-in-terms-of,純實現復用

鐵律:基類 private 成員在派生類中永遠不可訪問,無論繼承方式。訪問級別只能收窄,不能放寬。

構造與析構協作時序

  1. 構造順序:基類構造(按繼承列表順序)→ 成員子對象構造(按聲明順序)→ 派生類構造函數體。
  2. 析構順序:完全相反。派生類析構體 → 成員子對象析構 → 基類析構。
  3. 虛析構必要性:若基類指針刪除派生對象,基類必須聲明 virtual ~Base(),否則派生類析構不被調用導致資源洩漏。

拷貝構造函數在繼承體系中的正確寫法


class CCandyBox : private CBox {
public:
    // 派生類拷貝構造:先調用基類拷貝構造,再深拷貝自有資源
    CCandyBox(const CCandyBox& other)
        : CBox(other), // 基類部分拷貝
          m_Contents(new char[strlen(other.m_Contents)+1]) {
        strcpy_s(m_Contents, strlen(other.m_Contents)+1, other.m_Contents);
    }
    // 拷貝賦值同理:檢查自賦值、釋放舊資源、基類賦值、深拷貝新資源
    CCandyBox& operator=(const CCandyBox& other) {
        if (this != &other) {
            CBox::operator=(other); // 基類賦值
            delete[] m_Contents;
            m_Contents = new char[strlen(other.m_Contents)+1];
            strcpy_s(m_Contents, strlen(other.m_Contents)+1, other.m_Contents);
        }
        return *this;
    }
};

進階特性:final、友元與前向聲明

禁止繼承:final (C++11)


class CBox final { /* ... */ }; // 編譯器禁止 class Derived : CBox
// final 是上下文關鍵字,非保留字,可作變量名

友元:受控的封裝破例

  • 友元函數/類:可訪問 private/protected 成員。
  • 不具備傳遞性/繼承性:基類友元不可訪問派生類自有私有成員。
  • 典型用途:運算符重載(operator<< 需訪問私有數據)、工廠類創建私有構造對象、單元測試框架訪問內部狀態。

前向聲明:打破編譯依賴循環


// CBottle.h
class CCarton; // 前向聲明
class CBottle {
    friend CCarton::CCarton(const CBottle&); // 友元聲明需完整函數簽名
    double m_Height, m_d;
public:
    CBottle(double h, double d) : m_Height(h), m_d(d) {}
};

// CCarton.h
class CBottle; // 前向聲明
class CCarton {
    double m_Height, m_Width, m_Length;
public:
    CCarton(const CBottle&); // 參數為引用,僅需前向聲明
};

// CCarton.cpp
#include "CCarton.h"
#include "CBottle.h" // 實現處需完整定義
CCarton::CCarton(const CBottle& b) 
    : m_Height(b.m_Height), m_Length(4.0*b.m_d), m_Width(3.0*b.m_d) {}

規則:頭文件中僅用到指針/引用/返回類型 → 前向聲明;源文件實現需完整定義 → #include。不可用於:定義值類型成員、基類列表、sizeof、實例化模板。

最佳實踐總結

  1. 繼承建模「是一種」,復用實現用組合/私有繼承;public 繼承必須滿足里氏替換原則。
  2. 基類析構函數聲明 virtual,無例外。
  3. 資源管理類遵循三/五/零法則,派生類拷貝/移動操作必須顯式調用基類對應操作。
  4. 優先 public 繼承 + 虛函數實現多態,private/protected 繼承僅用於實現復用(策略模式可用組合替代)。
  5. 善用 final 封鎖不應擴展的類,override 強制檢查覆寫正確性。
  6. 友元最小化,僅用於語法必要場景(流運算符、特定工廠)。
  7. 前向聲明減少頭文件依賴,加速編譯,降低耦合。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved