2014-03-05 209 views
3

我想知道是否有無論如何,我的超類可以調用子類的函數initValues()而不必重寫構造函數?從超類訪問子類?

下面的代碼:

#ifndef VECTOR_MATH_H 
#define VECTOR_MATH_H 

#include "GL\glew.h" 

#include <iostream> 

namespace Math3d 
{ 

class Vector 
{ 
public: 
    Vector(int length=2) : v(new float[length]) { initValues(); } 
    ~Vector() { delete[] v; } 
protected: 
    virtual void initValues() 
    { 
     std::cout << "Vector" << std::endl; 
    } 
    float* v; 
}; 

class Vector3 : public Vector 
{ 
public: 
protected: 
    void initValues() 
    { 
     std::cout << "Vector3" << std::endl; 
    } 
}; 

} 

#endif 

然後我創建這樣一個變量: 的Vector3 VEC;

然後我想要調用子類Vector3的initValues() 方法 。

這可能嗎?

+0

似乎是重複的:http:// stackoverflow。com/questions/7644154/calling-base-class-virtual-method-by-derived-class-virtual-method –

+0

@StevenBehnke看起來像OP的另一種要求。 –

+0

它可能是,但反過來對我沒有任何意義。 Vector如何知道派生類? –

回答

2

簡要的回答:不,你不能。

長答案:直到派生類構造函數被調用後,對象的虛擬表才被充實。在基類構造函數中,虛擬表指向函數的基類實現。如果基類有一個實現,那麼該函數將被調用。如果基類沒有實現,則會發生依賴於平臺的錯誤/異常。

+0

至少有可能,看看我的答案。 –

+0

正如您已經顯示的那樣,在類模板中使用常規函數是可能的,並且它是衆所周知的[好奇重複的模板模式](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)。這是不可能的使用虛擬功能。 –

+0

實際上,對於CRTP而言,函數是否聲明爲虛擬或完全沒有關係。 –

2

如果要同時調用父類initValues(),然後將子類initValues()你將需要顯式調用Vector::initValues()Vector3::initValues()因爲動態調度總是會調用該方法的更爲特殊的版本:

void Vector3::initValues() { 
    Vector::initValues(); 
    other specific code; 
} 

如果您真的希望大家都能夠在你想,那麼你將需要第二個方法的順序:

class Vector { 
    protected: 
    void initValues() { 
     // common init 
     specificInitValues(); 
    } 

    virtual void specificInitValues() = 0; 
}; 

class Vector3 : public Vector { 
    protected: 
    virtual void specificInitValues() override { 
    // specific init 
    } 
}; 
+1

我回答了同樣的問題。但是OP從基類構造函數調用'initValues()',所以我覺得他們可能真的在問一些不同的東西。 – juanchopanza

+0

您無法從基類安全地調用派生類的方法,因爲該對象可能只是基類的對象,或屬於非常不同的派生類。重新考慮你的設計,這應該永遠不需要。 – vonbrand

0

你不能用動態多態性做到這一點(使用virtual功能表,又名。如vtable),因爲在超類試圖調用虛方法的時候,只有雙類被構造出來,並且子類initValues()的實現不能從完全構造的vtable中調用。

有兩種方法來解決這個問題:

1.讓您initValues()方法公開,並要求其施工後從客戶稱爲

2.你可以做些什麼來實現這種行爲,就是用靜態的,而不是多態:

template<class Derived> 
class VectorSuper 
{ 
public: 
    VectorSuper(int length=2) 
    : v(new float[length]) 
    { 
     static_cast<Derived*>(this)->initValues(); 
    } 
    ~VectorSuper() { delete[] v; } 
protected: 
    void initValues() // Note, no virtual 
    { 
     std::cout << "VectorSuper" << std::endl; 
    } 
    float* v; 
}; 

class VectorSub 
: public VectorSuper<VectorSub> 
{ 
protected: 
    void initValues() // Note, no virtual 
    { 
     VectorSuper<VectorSub>::initValues(); 
     std::cout << "VectorSub" << std::endl; 
    } 
} 

後一種方式可能會查詢超類中實現的抽象接口的某些進一步區別,以便在不知道約VectorSub且不需要的上下文中合理使用。

class AbstractVector 
{ 
public: 
    virtual ~AbstractVector() = 0; 
    // example interface 
    virtual float operator[](int index) const = 0; 
}; 

template<class Derived> 
class VectorSuper 
: public AbstractVector 
{ 
public: 
    VectorSuper(int length_=2) 
    : length(length_), v(new float[length]) 
    { 
     static_cast<Derived*>(this)->initValues(); 
    } 
    ~VectorSuper() { delete[] v; } 

    virtual float operator[](int index) const 
    { 
     if(index >= length || index < 0) 
     { 
      throw std::invalid_argument("index"); 
     } 
     return v[index]; 
    } 
protected: 
    // ... as before 

    int length; // Remember length additionally! 
    float* v; 
};