基類別為類別模板 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++ 標準要求不查找相依基類別的非相依名稱。
this-> 前綴(將名稱變為相依名稱)void sendClearMsg(const MsgInfo& info) {
log("before");
this->sendClear(info); // 依賴 Company,延至實例化期查找
log("after");
}
using 宣告引入基類別名稱template
class LoggingMsgSender : public MsgSender {
public:
using MsgSender::sendClear; // 告訴編譯器假設基類別有此成員
void sendClearMsg(const MsgInfo& info) {
log("before");
sendClear(info); // 正常編譯
log("after");
}
};
void sendClearMsg(const MsgInfo& info) {
log("before");
MsgSender::sendClear(info); // 強制指定
log("after");
}
缺點: 若 sendClear 為 virtual,明確限定會關閉虛擬綁定,改為靜態呼叫。
若實際具體化為 LoggingMsgSender<CompanyZ> 並呼叫 sendClearMsg,編譯器在實例化時會發現 MsgSender<CompanyZ> 缺少 sendClear,報錯於呼叫點而非定義點。這正是「早期診斷」與「晚期診斷」的權衡:C++ 選擇在定義期拒絕非相依名稱,強制開發者明確宣告意圖。
this->member — 簡單、保留虛擬綁定。using Base::member — 語意清晰、適合多重引入。Base::member — 明確但關閉虛擬函式多型,謹慎使用。核心原則:在衍生類別模板中存取模板化基類別成員時,必須讓名稱成為相依名稱,才能通過標準編譯器檢查。