2012-03-23 77 views
3

小結:在搜索標準C++設計圖案的用於通過構造加載不同的文件C++設計模式:多種方式來加載文件

我有一個Base類的一些功能,將被所有派生類可以使用(例如,Derived_ADerived_B)。主要區別在於Derived_ADerived_B覆蓋load函數,該函數用於由構造函數加載數據文件(load也可能在構造函數之外顯式調用)。

我跑進從這個意想不到的問題:load功能由構造稱爲治療類爲Base類型,但是當我使用一個默認的構造函數和顯式調用load功能,則虛函數表允許預期load函數被調用。 (我最近使用Python進行編程,我相信,由於打字很弱,總是會調用預期的功能)。這是一個經典的問題,但我無法找到一種方法來做到這一點。

以同樣的方式,我真的很喜歡Base::load是純粹的虛擬/抽象(只有派生類將被實例化);然而,這不會編譯(我相信,因爲編譯器認爲純虛函數會被調用)。

你能幫忙嗎?

輸出:

加載瓦特/構造:
基地::負載FILE_A
基地::負載FILE_B加載瓦特/功能交結構:
Derived_A ::負載FILE_A
Derived_B :: load file_B

代碼:

#include <iostream> 
#include <string> 

class Base 
{ 
public: 
    Base() {} 
    Base(std::string x) 
    { 
    load(x); 
    } 
    virtual void load(std::string x) 
    { 
    std::cout << "\tBase::load " << x << std::endl; 
    } 
}; 

class Derived_A : public Base 
{ 
public: 
    Derived_A() {} 
    Derived_A(std::string x): Base(x) {} 
    void virtual load(std::string x) 
    { 
    std::cout << "\tDerived_A::load " << x << std::endl; 
    } 
}; 

class Derived_B : public Base 
{ 
public: 
    Derived_B() {} 
    Derived_B(std::string x): Base(x) {} 
    void virtual load(std::string x) 
    { 
    std::cout << "\tDerived_B::load " << x << std::endl; 
    } 
}; 

int main() 
{ 
    // simpler code, but it doesn't behave as I hoped 
    std::cout << "Loading w/ constructor:" << std::endl; 
    Base*der_a = new Derived_A(std::string("file_A")); 
    Base*der_b = new Derived_B(std::string("file_B")); 

    // this is what I want to do 
    std::cout << "Loading w/ function post construction:" << std::endl; 
    der_a = new Derived_A; 
    der_a->load(std::string("file_A")); 
    der_b = new Derived_B; 
    der_b->load(std::string("file_B")); 
    return 0; 
} 

回答

2

您所看到的行爲得到了很好的C++定義 - 它只是沒有在這種情況下非常有用,因爲當你從Base::Base(std::string)調用load(std::string)類是不完全構造。

有兩個直接的方法:

一個

你可以使用它調用加載(也許持有到字符串也一樣)的容器類型。如果你需要堅持實例(例如他們可能有專門的錯誤信息),這可能更實用。

class Loader 
{ 
public: 
    Loader(Base* const p, const std::string& location) : d_base(p) 
    { 
     this->d_base->load(location); 
    } 

private: 
    std::unique_ptr<Base>d_base; 
private: 
    Loader(const Loader&) = delete; 
    Loader& operator=(const Loader&) = delete; 
}; 

在使用中:

std::cout << "Loading w/ Loader:\n"; 
Loader l_der_a(new Derived_A, "file_A"); 
Loader l_der_b(new Derived_B, "file_B"); 

你也可以使用一個輔助函數來解決:

class Base { 
public: 
    template<typename T> 
    static void Load(const std::string& x) 
    { 
     T().load(x); 
    } 

    Base() 
    { 
    } 

    Base(std::string x) 
    { 
     /* load(x); << see Load(const std::string&) */ 
    } 

    virtual ~Base() 
    { 
    } 

    virtual void load(std::string x) = 0; 
}; 

在使用中:

std::cout << "Loading w/ Base::Load<T>():\n"; 
Derived_A::Load<Derived_A>("file_A"); 
Derived_B::Load<Derived_B>("file_B"); 

然後還有其他幾種方法和變化 - 它取決於什麼最適合您的設計。用C++,你當然有選擇。

+1

我最終使用'loader'模式。非常感謝! – user 2012-03-26 19:44:06

2

您可以查閱"Named Constructor Idiom"

+0

+1好點,這是python鼓勵的。你知道我是否需要爲每個子類編寫命名構造函數?還是有辦法寫一次,以防止重複的代碼(它總是調用'load',然後可能是一些其他功能)。 – user 2012-03-23 14:43:25

+0

您沒有獲取需要文件的權限(試圖打開鏈接時出錯) – GameDeveloper 2015-08-29 16:49:28