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

C++ 箴言:如何在衍生類別模板中存取模板化基類別的名稱

     編輯:關於C++

問題情境

基類別為類別模板 MsgSender<Company>,衍生類別 LoggingMsgSender 需呼叫基類別方法 sendClear():

template
class MsgSender {
public:
    void sendClear(const MsgInfo& info) {
        Company c; c.sendCleartext(createMsg(info));
    }
    void sendSecret(const MsgInfo& info) { /* ... */ }
};

template
class LoggingMsgSender : public MsgSender {
public:
    void sendClearMsg(const MsgInfo& info) {
        log("before sending");
        sendClear(info); // 編譯錯誤:找不到 sendClear
        log("after sending");
    }
};

根本原因:兩階段名稱查找

編譯器解析衍生類別模板定義時,Company 尚未具體化,無法確定 MsgSender<Company> 內容。基類別可能被完全特化(如 MsgSender<CompanyZ> 移除 sendClear),導致介面不一致。為安全起見,C++ 標準要求不查找相依基類別的非相依名稱。

三種標準解法

1. 加上 this-> 前綴(將名稱變為相依名稱)

void sendClearMsg(const MsgInfo& info) {
    log("before");
    this->sendClear(info); // 依賴 Company,延至實例化期查找
    log("after");
}

2. using 宣告引入基類別名稱

template
class LoggingMsgSender : public MsgSender {
public:
    using MsgSender::sendClear; // 告訴編譯器假設基類別有此成員
    void sendClearMsg(const MsgInfo& info) {
        log("before");
        sendClear(info); // 正常編譯
        log("after");
    }
};

3. 明確指定基類別限定名稱

void sendClearMsg(const MsgInfo& info) {
    log("before");
    MsgSender::sendClear(info); // 強制指定
    log("after");
}

缺點: 若 sendClear 為 virtual,明確限定會關閉虛擬綁定,改為靜態呼叫。

實例化期的真相

若實際具體化為 LoggingMsgSender<CompanyZ> 並呼叫 sendClearMsg,編譯器在實例化時會發現 MsgSender<CompanyZ> 缺少 sendClear,報錯於呼叫點而非定義點。這正是「早期診斷」與「晚期診斷」的權衡:C++ 選擇在定義期拒絕非相依名稱,強制開發者明確宣告意圖。

總結:三大必記技巧

  1. this->member — 簡單、保留虛擬綁定。
  2. using Base::member — 語意清晰、適合多重引入。
  3. Base::member — 明確但關閉虛擬函式多型,謹慎使用。

核心原則:在衍生類別模板中存取模板化基類別成員時,必須讓名稱成為相依名稱,才能通過標準編譯器檢查。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved