3

在C++中探索基於策略的設計模式時,我偶然發現了一個我找不到解決方案的問題:如何編寫基於策略的類的複製和移動構造函數方式而不涉及策略類內的成員變量?基於策略的設計中的C++複製/移動構造函數

下面是一個例子:

class Foobase { 
public: 
    Foobase(int v) :val(v) { } 
protected: 
    int val; 
}; 

template <typename Base> 
class Foo : public Base { 
public: 
    Foo(int v):Base(v) { } 
    // how can I initialize Base() class without referring to it's protected members? 
    Foo(const Foo<Base>& other) :Base(other.val) { } 
}; 

int main() { 
    Foo<Foobase> foo(5); 
    auto foo2 = foo; 
} 

在上面的代碼中,複製的class Foo構造使用受保護成員變量初始化Base類。除上述以外是否還有其他方式可以初始化Base?這種情況下的最佳做法是什麼?

更新問題:

通過@LogicStuff答案澄清問題的拷貝構造函數部分,但是沒有接聽移動的構造問題。請參閱更新的示例代碼,其中class Foo也可以具有成員變量。

class Foobase { 
public: 
    Foobase(int v) :val(v) { } 
    Foobase(const Foobase&) = default; 
    Foobase(Foobase&&) noexcept = default; 
    Foobase& operator= (const Foobase&) = default; 
    Foobase& operator= (Foobase&&) noexcept = default; 
    void Print() const { 
    std::cout << val << std::endl; 
    } 
protected: 
    int val; 
}; 

template <typename Base> 
class Foo : public Base { 
public: 
    // works fine 
    Foo(std::string str, int v):Base(v), name(str) { } 

    // works fine 
    Foo(const Foo<Base>& other) :Base(other), name(other.name) { } 

    // I'm doubtful about this c'tor, if I move `other` for initializing Base, 
    // how can I initialize `name` variable? 
    Foo(Foo<Base>&& other) 
    :Base(std::move(other)), name(std::move(other.name) /* will this be valid?? */) { } 

    // can we have copy and assignment operator for this class? 

    void Print() { 
    std::cout << "name = " << name << std::endl; 
    Base::Print(); 
    } 

private: 
    std::string name; 
}; 

int main() { 
    Foo<Foobase> foo("foo", 5); 
    auto foo2 = std::move(foo); 
    foo2.Print(); 
} 
+0

爲什麼你首先定義拷貝構造函數?使用零規則。 – milleniumbug

+0

這裏複製構造函數是一個例子,我將在實際用例場景中遵循5的規則! – Pranav

+0

不是五的規則。 *零規則*。在你的情況下,'Foobase'遵循Rule of Zero,'Foo'裏面的成員都不需要特殊的處理,所以你*不會爲'Foo'類編寫任何*特殊成員,因爲默認的成員將會做所有需要的。 – milleniumbug

回答

2

你可以簡單地使用Base的拷貝構造函數:

Foo(const Foo<Base>& other) : Base(other) { } 

或者不定義它的一切,把它留給編譯器,如果你不打算做些額外的事情存在。

實際上,它可以是這樣的,你的例子仍將編譯:

template <typename Base> 
class Foo : public Base { 
public: 
    using Base::Base; 
}; 

您的編輯後:

現在你必須補充一個構造函數接受兩個參數(如你做的):

template <typename Base> 
class Foo : public Base { 
public: 
    Foo(std::string str, int v) : Base(v), name(str) { } 

    void Print() { 
    std::cout << "name = " << name << std::endl; 
    Base::Print(); 
    } 

private: 
    std::string name; 
}; 

但是y你還定義了特殊的成員函數,這些函數將由編譯器完全相同地生成(這意味着它們是正確的)。您的原始示例也是這種情況。 Foo這兩個版本都是可移動的。

+0

謝謝@LogicStuff的答案。它確實回答了我有關複製構造函數的問題,但可能不回答它的移動構造函數部分。也許我錯過了什麼?請參閱最新的問題。謝謝! – Pranav

+0

請確實試着遵守3/5/0的規則。這個問題純粹是基於你沒有這樣做。 – LogicStuff

+0

對不起,我只是沒有定義所有的構造函數來使用較小的示例代碼。 – Pranav

相關問題