簡體   English   中英

覆蓋C ++中的成員變量

[英]Overriding a member variable in C++

我在某些C ++代碼中遇到了一個棘手的問題,最容易使用代碼來描述。 我有一些類似的課程:

class MyVarBase
{
}

class MyVar : public MyVarBase
{
    int Foo();
}

class MyBase
{
public: 
    MyBase(MyVarBase* v) : m_var(v) {}
    virtual MyVarBase* GetVar() { return m_var; }
private:
    MyVarBase* m_var;
}

我還擁有MyBase的子類,該子類需要具有MyVar類型的成員,因為它需要調用Foo。 不能將Foo函數移到MyVarBase中。 這樣做是否有意義:

class MyClass : public MyBase
{
public:
    MyClass(MyVar* v) : MyBase(v), m_var(v) {}
    MyVar* GetVar() { return m_var; }
private:
    MyVar* m_var;
}

這似乎可行,但看起來確實很糟糕,我不確定是否會導致內存泄漏或破壞復制構造函數。 我的其他選擇可能是在MyClass中將MyVar變量命名為其他名稱,但使其等於基數中的m_var指針,或者在MyVar類型上對MyBase進行模板化。

所有這些選項似乎都不理想,因此我想知道是否有人遇到了這種情況,以及是否有使其工作的好方法。

正確的方法是僅在基類中具有變量。 如派生類所知,它必須是動態類型MyVar ,這是完全合理的:

class MyClass : public MyBase
{
public:
    MyClass(MyVar* v) : MyBase(v) {}
    MyVar* GetVar() { return static_cast<MyVar*>(MyBase::GetVar()); }
}

由於myvar可以從MyVarBase得出,不同的返回類型的GetVar仍然堅持工作,如果GetVar是虛擬的(如這里的情況)。 請注意,使用該方法,在MyBase中必須沒有任何函數可以將指針重置為明顯不同的內容。

請注意,在這種情況下, static_cast是正確的轉換。 如一位評論者所建議,使用dynamic_cast會告訴GetVar的讀者和用戶MyBase::GetVar()可以返回指向非MyVar類型的對象的指針。 但這並不能反映我們的意圖,因為您只能通過MyVar。 因此,在軟件開發中最重要的是。 可以做的是斷言它不是null。 它將在運行時中止,並在項目的調試版本中顯示錯誤消息:

MyVar* GetVar() { 
    assert(dynamic_cast<MyVar*>(MyBase::GetVar()) != 0);
    return static_cast<MyVar*>(MyBase::GetVar()); 
}

在不了解更多上下文的情況下,很難確定,但是我首先要重新考慮您是否需要此類的類層次結構。 您是否真的需要MyVarBase和MyBase類? 您能擺脫合成而不是繼承嗎? 如果您將適用於上述類的函數和類模板化,那么也許根本就不需要類繼承。 也許CRTP也可以提供幫助。 在C ++中,有許多替代方法可以使用虛擬函數(在某種程度上,通常是繼承)。

無論如何,您自己建議的解決方案當然不會泄漏任何內存(因為它不會分配任何內存),也不會破壞默認的副本構造函數(因為它僅執行成員級副本。現在,您只需要一個額外的內存即可)派生類中的成員,但也會被復制)。 當然,您還會遇到使兩個變量保持同步的另一個問題,因此我仍然不太喜歡這種解決方案。

或者,您可以從基類中刪除變量。 使GetVar()函數成為純虛擬的,以便僅在派生類中實現,派生類可以按自己喜歡的任何方式定義成員變量。

我認為您提到模板可能是一個不錯的選擇,所以類似:

class MyVarBase
{
};

class MyVar : public MyVarBase
{
  int Foo();
};

template <class T> class MyBase
{
public: 
  MyBase(T* v) : m_var(v) {}
  T* GetVar() { return m_var; }

private:
  T* m_var;
};

class MyClass : public MyBase<MyVar>
{
public:
  MyClass(MyVar* v) : MyBase(v) {}
};

但是,這取決於您可以實際更改的類。 同樣,“ MyClass”定義可能是多余的,除非它具有MyBase類之外的其他成員。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM