आभासी विरासत में से कुछ चतुर उपयोग CloneableMixin :: क्लोन बेस :: क्लोन ओवरराइड करने की अनुमति कर सकते हैं?
आपका CloneableMixin<Base,Derived>
Base
का कोई भी तरीका ओवरराइड नहीं कर सकते हैं - या तो polymorphically या छिपने से - क्योंकि CloneableMixin<Base,Derived>
Base
से प्राप्त नहीं है।
class Derived : public CloneableMixin<Base,Derived> {....};
Base
वारिस होगा -
दूसरी ओर, यदि CloneableMixin<Base,Derived>
Base
से प्राप्त किए गए आपके पास कोई भी जरूरत है कि यह एक mixin होने के लिए है, क्योंकि होगा।
तो अपने उदाहरण की जरूरतों के लिए समाधान यहाँ सचित्र पर्याप्त होगा:
#include <iostream>
// cloner v1.0
template <class Base, class Derived>
struct cloner : Base
{
Base *clone() const override {
return new Derived(dynamic_cast<const Derived &>(*this));
}
~cloner() override {};
};
struct Base
{
virtual Base * clone() const = 0;
Base() {
std::cout << "Base()" << std::endl;
}
virtual ~Base() {
std::cout << "~Base()" << std::endl;
}
};
struct A : cloner<Base,A>
{
A() {
std::cout << "A()" << std::endl;
}
~A() override {
std::cout << "~A()" << std::endl;
}
};
int main()
{
A a;
Base * pb = a.clone();
delete pb;
}
(यदि आप इसके बजाय सी ++ 11 से करने के लिए सी ++ 03 मानक संकलन कर रहे हैं, तो आप बस हटा सकते हैं override
कीवर्ड की घटनाओं।)
यह समाधान कुछ और वास्तविक सांसारिक वर्ग पदानुक्रम, उदाहरण के लिए नीचे टूट जाएगा
#include <iostream>
#include <memory>
using namespace std;
// cloner v1.0
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
};
/* Abstract base class `abstract` keeps the state for all derivatives
and has some pure virtual methods. It has some non-default
constructors.
*/
struct abstract
{
virtual ~abstract() {
cout << "~abstract()" << endl;
}
int get_state() const {
return _state;
}
void run() {
cout << "abstract::run()" << endl;
a_root_method();
another_root_method();
}
virtual void a_root_method() = 0;
virtual void another_root_method() = 0;
virtual abstract * clone() const = 0;
protected:
abstract()
: _state(0) {
cout << "abstract(): state = " << get_state() << endl;
}
explicit abstract(int state) : _state(state) {
cout << "abstract(" << state << ") : state = "
<< get_state() << endl;
}
int _state;
};
/* Concrete class `concrete` inherits `abstract`
and implements the pure virtual methods.
It echoes the constructors of `abstract`. Since `concrete`
is concrete, it requires cloneability.
*/
struct concrete : cloner<abstract,concrete>
{
concrete() {
cout << "concrete(): state = " << get_state() << endl;
}
explicit concrete(int state) : abstract(state) { //<- Barf!
cout << "concrete(" << state << ") : state = "
<< get_state() << endl;
}
~concrete() override {
cout << "~concrete()" << endl;
}
void a_root_method() override {
++_state;
cout << "concrete::a_root_method() : state = "
<< get_state() << endl;
}
void another_root_method() override {
--_state;
cout << "concrete::another_root_method() : state = "
<< get_state() << endl;
}
};
int main(int argc, char **argv)
{
concrete c1;
unique_ptr<abstract> pr(new concrete(c1));
pr->a_root_method();
pr->another_root_method();
unique_ptr<abstract> pr1(pr->clone());
pr1->a_root_method();
return 0;
}
जब हम इस निर्माण करने के लिए प्रयास करते हैं, संकलक एक त्रुटि पर प्रारंभ abstract(state)
concrete
की constuctor (Barf!
टिप्पणी पर) में दे देंगे, कह रही::
Template Method Pattern के इस चित्र में
error: type 'abstract' is not a direct or virtual base of 'concrete'
या उस प्रभाव के लिए शब्द। वास्तव में, concrete
का प्रत्यक्ष आधार abstract
लेकिन cloner<abstract,concrete>
नहीं है। हालांकि, हम निर्माता पुनर्लेखन नहीं कर सकते हैं के रूप में:
/*Plan B*/ explicit concrete(int state) : cloner<abstract,concrete>(state){....}
क्योंकि वहाँ है
cloner<abstract,concrete>::cloner<abstract,concrete>(int)
जैसी कोई निर्माता है लेकिन संकलक निदान के एक ठीक चलता है। यह वर्चुअल विरासत सहायता कर सकता है। हम abstract
जरूरत concrete
के आभासी आधार है, जो प्रभावी ढंग से मतलब है "concrete
की मानद प्रत्यक्ष आधार" बनने के लिए, और हम सिर्फ B
बनाने cloner<B,D>
के आभासी आधार से कि प्राप्त कर सकते हैं:
// cloner v1.1
template<class B, class D>
struct cloner : virtual B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
};
abstract(): state = 0
concrete(): state = 0
concrete::a_root_method() : state = 1
concrete::another_root_method() : state = 0
concrete::a_root_method() : state = 1
~concrete()
~abstract()
~concrete()
~abstract()
~concrete()
~abstract()
अच्छे कारणों आभासी विरासत ओ से सावधान रहना करने के लिए कर रहे हैं:
कि के साथ, हम एक साफ निर्माण और उत्पादन एन सिद्धांत और कम से कम उन मामलों के लिए इसका उपयोग आरक्षित करने के लिए जिसमें आर्किटेक्चरल तर्क है - कामकाज के लिए नहीं, जैसा कि हमने अभी इसका उपयोग किया है।
हम इस समस्या के लिए आभासी विरासत के बिना ऐसा करने के लिए पसंद करते हैं, तो हम किसी भी तरह यह सुनिश्चित करना चाहिए कि cloner<B,D>
गूँज B
के किसी भी constuctor, मनमाने ढंग से B
के लिए के एक निर्माता नहीं है। फिर D
का कोई भी संबंधित कन्स्ट्रक्टर इसके प्रत्यक्ष आधार cloner<B,D>
जो भी तर्क हैं, आरंभ करने में सक्षम हो जाएगा।
इस के लिए सी ++ 03 एक pipedream है, लेकिन सी ++ 11 में मापदंडों variadic टेम्पलेट के जादू के साथ यह आसान है:
// cloner v1.2
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
// "All purpose constructor"
template<typename... Args>
explicit cloner(Args... args)
: B(args...){}
};
इस के साथ
, हम पुनर्लेखन कर सकते हैं concrete
निर्माता /*Plan B*/
, और के रूप में हमारे पास एक सही निर्माण और निष्पादन योग्य है।
http://stackoverflow.com/questions/9422760/inheritance-in-curiously-recurring-template-pattern-polymorphic-copy-c – TemplateRex
'बेस :: क्लोन' को संभावित रूप से 'आभासी' होने की आवश्यकता है संभावित संभावित डुप्लिकेट '= 0' वैध होने के लिए। – TemplateRex
@rhalbersma मुझे यकीन नहीं है कि यह काफी वही है। मेरे सभी क्लोनेबल वर्गों में समान आधार प्रकार नहीं होगा (उदा। 'बेस',' बेस 2')। – user