亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

請問在模板化派生類中,為什么我需要在成員函數中使用“this->”限定基類成員名稱?

請問在模板化派生類中,為什么我需要在成員函數中使用“this->”限定基類成員名稱?

C++
DIEA 2019-09-06 12:06:08
在模板化派生類中,為什么我需要在成員函數中使用“this->”限定基類成員名稱?當我研究Qt的源代碼時,我發現trolltech的人明確地使用this關鍵字來訪問析構函數中的字段。inline ~QScopedPointer(){     T *oldD = this->d;     Cleanup::cleanup(oldD);     this->d = 0;}那么,這個用法有什么意義呢?有什么好處嗎?編輯:對于那些投票支持關閉此問題的人,我懷疑這種用法適用于某些類繼承案例QScopedPointer類定義的一部分:template <typename T, typename Cleanup = QScopedPointerDeleter<T> >class QScopedPointer
查看完整描述

2 回答

?
慕斯709654

TA貢獻1840條經驗 獲得超5個贊

C ++答案(一般答案)

考慮一個Derived帶有模板基類的模板類:

template <typename T>class Base {public:
    int d;};template <typename T>class Derived : public Base<T> {
    void f () {
        this->d = 0;
    }};

this有類型Derived<T>,依賴的類型T。所以this有依賴類型。所以this->dd一個從屬名稱。在模板定義的上下文中查找從屬名稱作為非依賴名稱并在實例化的上下文中查找。

沒有this->,名稱d只會被查找為非依賴名稱,而不能找到。

另一種解決方案是d在模板定義中聲明:

template <typename T>class Derived : public Base<T> {
    using Base::d;
    void f () {
        d = 0;
    }};

Qanswer(具體答案)

d是...的成員QScopedPointer。它不是一個繼承的成員。this->這里沒有必要。

OTOH QScopedArrayPointer是一個模板類,d是模板基類的繼承成員:

template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >class QScopedArrayPointer : public QScopedPointer<T, Cleanup>

所以這里this->是必要的:

inline T &operator[](int i){
    return this->d[i];}

很容易看出,放在this->任何地方都比較容易。

了解原因

我想所有C ++用戶都不清楚為什么在非依賴基類中查找名稱而在依賴基類中查找名稱:

class Base0 {public:
    int nd;};template <typename T>class Derived2 : 
        public Base0, // non-dependent base
        public Base<T> { // dependent base
    void f () {
        nd; // Base0::b
        d; // lookup of "d" finds nothing

        f (this); // lookup of "f" finds nothing
                  // will find "f" later
    }};

“標準如此說”旁邊有一個原因:模板中名稱綁定的方式起作用。

在模板實例化時,模板可以具有后期綁定的名稱:例如,ff (this)。在Derived2::f()定義時,f編譯器不知道變量,函數或類型名稱。此時f可以引用的已知實體集是空的。這不是問題,因為編譯器知道它f稍后將作為函數名稱或模板函數名稱進行查找。

OTOH,編譯器不知道該怎么做d; 它不是(稱為)函數名稱。無法對非(調用)函數名稱進行后期綁定。

現在,所有這些看起來都像編譯時模板多態的基本知識。真正的問題似乎是:為什么不是d必然要Base<T>::d在模板定義的時間?

真正的問題是Base<T>::d在模板定義時沒有,因為那時沒有完整的類型Base<T>Base<T>聲明,但沒有定義!你可能會問:這是怎么回事:

template <typename T>class Base {public:
    int d;};

它看起來像一個完整類型的定義!

實際上,直到實例化,它看起來更像是:

template <typename T>class Base;

到編譯器。無法在類模板中查找名稱!但僅限于模板特化(實例化)。模板是一個工廠,使模板專業化,模板不是一組模板專業化。編譯器可以查找dBase<T>任何特定類型T,但它無法查找d在類模板Base。在T確定類型之前,Base<T>::d仍然是抽象的Base<T>::d; 只有當類型T已知時,才Base<T>::d開始引用類型的變量int。

這樣做的結果是類模板 Derived2具有完整的基類,Base0但是具有不完整的(前向聲明的)基類Base。僅對于已知類型T,“模板類”(類模板的特化)Derived2<T>具有完整的基類,就像任何普通類一樣。

你現在看到:

template <typename T>class Derived : public Base<T>

實際上是一個基類規范模板(一個制作基類規范的工廠),它遵循模板內基類規范的不同規則。

備注:讀者可能已經注意到我在解釋結束時編寫了一些短語。

這是非常不同的:這里d是一個限定名稱Derived<T>,Derived<T>因為它T是一個模板參數。即使不是(稱為)函數名,限定名也可以延遲綁定。

另一個解決方案是:

template <typename T>class Derived : public Base<T> {
    void f () {
        Derived::d = 0; // qualified name
    }};

這是等效的。

如果你認為在定義里面Derived<T>,Derived<T>作為一個已知的完整類的處理有時和作為一個未知的類在其他時候不一致,那么,你是對的。



查看完整回答
反對 回復 2019-09-10
?
慕無忌1623718

TA貢獻1744條經驗 獲得超4個贊

我猜它應該與Cleanup()例程的重載使用有關。傳遞的類型由模板類型T顯式控制,而模板類型T又可以控制調用哪個重載版本的Cleanup()。


查看完整回答
反對 回復 2019-09-10
  • 2 回答
  • 0 關注
  • 636 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號