2016-05-01 57 views
1

我無法從父C++構造函數訪問子類中的字段,我無法使用模板,因爲上游項目沒有使用它們。訪問在沒有模板的構造函數中被重寫的字段

這是工作的Python原型,我嘗試在C++中重新實現。代碼包含兩個驅動程序類 - 一個孩子和一個父代,父代在初始化期間打印該類的name

class Driver(object): 
    name = "Unknown" 
    def __init__(self): 
    print(self.name) 

class SpecificDriver(Driver): 
    name = "Specific" 
    def __init__(self): 
    super(SpecificDriver, self).__init__() 

Driver() 
SpecificDriver() 

這將打印兩個字符串來安慰

Unknown 
Specific 

在C++不能訪問重寫name的樣子,因爲name沒有在這一點上存在 - Call child method from parent constructor。所以也許有另一種方式獲取驅動程序name打印初始化?

UPDATE(2018):此問題的原始標題是「在C++中初始化期間打印重寫的子字段,而沒有模板」,它被關閉得太寬泛。

+0

你可以使用靜態多態性又名CRTP。 –

+0

@πάνταῥεῖ是否需要使用模板?在我修補的代碼庫中,我沒有看到它們,它看起來並不簡單。 –

+0

是的,這需要使'Driver'成爲一個模板化的基類,它將派生類作爲類型參數。因此,您可以在每個要訪問「SpecificDriver」成員的地方使用'static_cast (this)'。很簡單恕我直言。 –

回答

2

儘管您要求在沒有模板的情況下這樣做,但它是從基類構造函數中完成此操作的唯一方法。

下面是一個示例,應該怎麼做:

struct IDriver { 
    // Public virtual API: 
    virtual void func1() = 0; 
    // ... 
    virtual ~IDriver() {} 
}; 

template<typename Derived> 
class Driver : public IDriver { 
public: 
    Driver() { 
     std::cout << "Driver" << std::endl; 
     std::cout << static_cast<Derived*>(this)->name() << std::endl; 
    } 
}; 

class SpecificDriver : public Driver<SpecificDriver> { 
public: 
    // Public virtual API: 
    virtual void func1(); 
    std::string name() const { return "SpecificDriver"; } 
    // or use typeid(SpecificDriver).name() if you prefer 
}; 

int main() { 
    SpecificDriver sd; 
} 

Live Demo


至於您的評論:

是否可以使用其他的init()函數在@tobspr方法,但使名稱而不是函數調用的字段?

好,因爲類名稱是這些類的靜態屬性,無論如何,你可以使用一個static const場類似如下:

template<typename Derived> 
class Driver : public IDriver { 
public: 
    Driver() { 
     std::cout << name << std::endl; 
     std::cout << Derived::name << std::endl; 
    } 

private: 
    static const std::string name; 
}; 

template<typename Derived> 
const std::string Driver<Derived>::name = "Driver"; 

class SpecificDriver : public Driver<SpecificDriver> { 
public: 
    static const std::string name; 
}; 

const std::string SpecificDriver::name = "SpecificDriver"; 

int main() { 
    SpecificDriver sd; 
} 

Live Demo

甚至簡化使用typeid()

#include <iostream> 
#include <string> 
#include <typeinfo> 

template<typename Derived> 
class Driver { 
public: 
    Driver() { 
     std::cout << typeid(*this).name() << std::endl; 
     std::cout << typeid(Derived).name() << std::endl; 
    } 
}; 

class SpecificDriver : public Driver<SpecificDriver> { 
}; 

int main() { 
    SpecificDriver sd; 
} 

Live Demo

+0

是否可以像@tobspr方法那樣使用額外的'init()'函數,但是將'name'作爲一個字段而不是函數調用? –

1

假設您有兩個Base Base和Derived類,Base構造函數不知道Derived類的任何內容,這使得無法區分這兩種類型。

既然你也不能(不應該)調用在構造虛擬方法,一個常見的模式是讓一個init方法:

struct Base { 
    virtual std::string get_name() { return "Base"; } 
    void init() { std::cout << get_name(); } 
}; 

struct Derived : public Base { 
    virtual std::string get_name() { return "Derived"; } 
}; 

// Later on .. 
Base b; 
b.init(); // Should print "Base" 

Derived d; 
d.init(); // Should print "Derived" 

正如你所看到的,這絕對不是簡單的解決方案。在這種情況下使用模板肯定會更好。

+0

我試圖在類初始化中使用新的'init'方法,它不起作用,可能是因爲它沒有創建 - http://codepad.org/OTXOdVNC也許有一種方法可以訪問派生類的靜態屬性? –

+0

爲什麼無法將「基本」和「派生」定義爲類屬性而不是方法? –

相關問題