2014-02-17 64 views
0

我想要一個非虛擬的基類方法調用覆蓋基類的虛擬方法之一的派生方法。對於我的生活,我無法實現它的工作。請參見下面的代碼:已解決:從基類內調用派生類方法?

public ref class BaseClass 
{ 
    virtual void OverriddenMethod(){} 

    void Run() 
    { 
     // Do some initial work here. 

     // Call the derived class's version of OverridenMethod to do final work: 
     OverriddenMethod(); 
    } 
}; 

public ref class DerivedClass : public BaseClass 
{ 
    virtual void OverriddenMethod() override 
    { 
     // Do some final work here. 
    } 
}; 

int main() 
{ 
    DerivedClass^ DC = gcnew DerivedClass(); 
    DC->Run(); 
} 

使用上面的代碼,基類的OverriddenMethod()被調用,而不是派生類的OverriddenMethod(),這不是我想要的。我的印象是,當使用多態時,對被覆蓋的基類方法的調用應該調用派生類的重寫方法。

我已經使用抽象也嘗試:

public ref class BaseClass abstract 
{ 
    virtual void OverriddenMethod() abstract; 

    void Run() 
    { 
     // Do some initial work here. 

     // Call the derived class's version of OverridenMethod to do final work: 
     OverriddenMethod(); 
    } 
}; 

public ref class DerivedClass : public BaseClass 
{ 
    void OverriddenMethod() 
    { 
     // Do some final work here. 
    } 
}; 

int main() 
{ 
    DerivedClass^ DC = gcnew DerivedClass(); 
    DC->Run(); 
} 

但這給出了C3278編譯器錯誤時OverriddenMethod被稱爲BaseClass的內部(接口方法「接口方法」將在運行時失敗的直接調用)::運行()定義。

我在這裏做錯了什麼?謝謝大家!

編輯: 通過下面的答案,我能夠找到問題。這裏是解決方案:

public ref class BaseClass abstract 
{ 
    virtual void BaseClass::OverriddenMethod() abstract; 

    void BaseClass::Run() 
    { 
     // Do some initial work here. 

     // Call the derived class's version of OverridenMethod to do final work: 
     BaseClass::OverriddenMethod(); // DONT DO THIS!!!!!!!! 
     OverriddenMethod(); // DO THIS INSTEAD!!!!! 
    } 
}; 

的問題,在這裏是因爲我使用的定義一個頭和我的基類的實現一個CPP文件。在cpp文件中,我通常使用ClassName :: MemberName表示法來引用任何ClassName的成員。但是,在這種情況下這樣做會強制基類的虛方法在派生類中被重寫的方法調用intsead。

這就是爲什麼在使用abstract關鍵字時,在調用基類的Run()定義內部的OverriddenMethod()時發生C3278錯誤。因爲我調用了BaseClass :: OverriddenMethod(),它指向的只是一個抽象定義。

我真的很討厭這樣的愚蠢,極易忽略的問題。

+2

錯誤的語言標記。 – juanchopanza

+0

Mgetz:感謝您指點我的文章。但是,它僅討論使用基類和派生類的引用在外部調用重寫的方法。我的問題是從基類內調用重寫的方法。另外,我在頂端示例中使用覆蓋,我沒有在第二個示例中使用,因爲它使用的是抽象。 – pcdangio

+0

@pcdangio無論在這種情況下,你都需要使用'override'。另外請注意,您需要設置訪問修飾符,以便導出的類可以覆蓋基類 – Mgetz

回答

1

首先,至少您的第一個代碼示例不應該被編譯,因爲方法Run具有私有訪問控制。

我試着用一些修改你的代碼名稱爲簡單起見,我得到了所需的結果

#include "stdafx.h" 

using namespace System; 

public ref class A 
{ 
public: 
    void f() { g(); } 
    virtual void g() { Console::WriteLine("A::g()"); } 
}; 

public ref class B : public A 
{ 
public: 
    virtual void g() override { Console::WriteLine("B::g()"); } 
}; 


int main(array<System::String ^> ^args) 
{ 
    A ^pa = gcnew B(); 
    pa->f(); 
    return 0; 
} 

輸出是

B::g() 

或者類可以被定義爲

public ref class A 
{ 
public: 
    void f() { g(); } 
protected: 
    virtual void g() { Console::WriteLine("A::g()"); } 
}; 

public ref class B : public A 
{ 
protected: 
    virtual void g() override { Console::WriteLine("B::g()"); } 
}; 

結果與導出的c的虛函數相同lass被稱爲。

+0

注意:'override'不需要'virtual' – Mgetz

+0

@Mgetz您錯了。至少MS VC++ 2010編譯器要求即使存在重寫也必須指定虛擬。 –

+0

有趣... VS2013不......因爲我的回答編譯和運行在/ clr-pure就好了 – Mgetz

相關問題