لا يمكن إجراء نسخ بناء دون إنشاء وظيفة صريحة في فئة القاعدة الافتراضية الخالصة؟
سؤال
هدفي هو القيام بنسخة عميقة من الفصل ، ولكن الفئة الافتراضية تسبب المتاعب.
#include<iostream>
using namespace std;
class Vir//pure virtual class
{
public:
virtual void hi()=0;
};
class Handler:public Vir
{
public:
int i;
Handler() {}
Handler(int val):i(val) {}
void hi() {cout<<"Value of i="<<i<<endl;}
int getI() const {return i;}
void setI(int j) {i=j;}
};
class ControlPanel
{
public:
Vir *v;
ControlPanel(const ControlPanel& c)//copy constructor
{
v=new Handler;
v->setI(c.getI());
}
int getI()const {return v->getI();}
void initialize() {v=new Handler(10);}
void hi() {v->hi();}
ControlPanel() {}
~ControlPanel() {delete v;}
};
int main()
{
ControlPanel cc;
cc.initialize();
cc.hi();
ControlPanel bb(cc);//copying cc into bb
}
رسالة خطأ التجميع:
test.cpp: In copy constructor ‘ControlPanel::ControlPanel(const ControlPanel&)’:
test.cpp:28: error: ‘class Vir’ has no member named ‘setI’
test.cpp: In member function ‘int ControlPanel::getI() const’:
test.cpp:30: error: ‘class Vir’ has no member named ‘getI’
أخطط للحصول على الكثير من فصول المعالج (مثل Handler1 ، Handler2 وما إلى ذلك) التي ترث من VIR وستكون لها أعضاء فريدين (مثل Float A ؛ أو Double B ؛ إلخ). لذلك ليس من المنطقي بالنسبة لي الحفاظ على جميع وظائف Getter & Setter لجميع فئات المعالج في فئة VIR. أريد أن أبقي أساليب getter و setter في فصول المعالج لأن الأعضاء فريدون في فصول المعالج. المترجم لا يسمح لي بالقيام بذلك. مساعدة؟
المحلول
ربما أفتقد شيئًا ولكن ألا تكون أفضل مع افتراضي clone
طريقة على Vir
؟ هذا يعني أنه يمكنك تجنب المصبوب السيئ في ControlPanel
نسخ مُنشئ في إجابتك الخاصة. هذا هو نفسه الذي يقترحه Andrew Aylett في إجابته مع duplicate
يتم استخدامها بدلاً من clone
.
شيء مثل
class Vir
{
public:
virtual Vir* clone() const = 0;
...
};
الذي يتم تنفيذه في Handler
ان نكون
Handler* Handler::clone() const
{
return new Handler( *this );
}
لاحظ استخدام نوع الإرجاع المتغير أي Handler::clone
يسمح له بإعادة أ Handler*
بدلا من مجرد أ Vir*
وما زالت تجاوزًا صحيحًا Vir::clone
.
هذا يجعل ControlPanel
نسخ المنشئ ببساطة
ControlPanel( const ControlPanel& c )
: v( c.v->clone() )
{
}
نصائح أخرى
أضف duplicate()
الوظيفة إلى فئتك التجريدية ، والتي (في كل فئة مشتقة) تنشئ مثيلًا جديدًا مع القيم الصحيحة ويعيده. بدلا من ذلك ، النظر copyFrom(Abs other)
الوظيفة التي تتحقق للتأكد من أنك تنسخ من النوع الصحيح ، وإذا كان الأمر كذلك ، فإن نسخ الحقول خارج.
بشكل عام ، إذا كانت فئة ControlPanel الخاصة بك لديها إشارة إلى كائن ABS ، فلا ينبغي أن تحاول القيام بازدواجها عن طريق فحص كائن المعالج الخرساني ، فيجب أن يمرر الازدواجية إلى وظيفة افتراضية على هذا الكائن.
لماذا يسمح لك المترجم؟ هذه الطرق ليست على تلك الواجهة.
يمكنك استخدام نمط المصنع لإنشاء الخاص بك Vir
, ، لتجنب الاضطرار إلى إضافة جميع المُنشئين إلى Vir
واجهة. يجب عليك أيضًا التفكير في استخدام راي لتجنب تهيئة () وظائف النمط.
يتغيرون Vir *v
ل Handler *v;
ومعرفة ما إذا كان الرمز الخاص بك يجمع أم لا.
فصلك Vir
لا يعلن/تحديد setI()
و getI()
وظائف الأعضاء.
أو تحديد Vir
مثل
class Vir//pure virtual class
{
public:
virtual void hi()=0;
virtual int getI()const =0;
virtual void setI(int)=0;
};
عليك أن تحدد getI
و setI
كما (نقية) افتراضية في Vir
لجعلها متاحة عبر الفئات الفرعية. بأي حال من الأحوال حول هذا.
كما اقترح ستيف ، أجب على سؤالي الخاص لأن صديقًا أعطاني حلاً. آمل أن يكون هذا مفيدًا لأي شخص لديه مسألة كيفية القيام بنسخة عميقة في C ++ حيث قد يكون الفصل الافتراضي حاجزًا. أملي أن يجد هذا نفعا.
#include<iostream>
using namespace std;
class Vir//pure virtual class
{
public:
virtual void hi()=0;
virtual int getI() {std::cout << "Inside Base class" << std::endl;}
virtual void setI(int i) {cout<<"In base"<<endl;}
virtual int getX() {}
virtual void setX(int x) {}
};
class Model
{
public:
int x;
Model(const Model& mm) {x=mm.x;}
Model():x(555) {cout<<"Model constructor called"<<endl;}
int getX() {return x;}
void setX(int xx) {x=xx;}
};
class Handler:public Vir
{
public:
int i;
Model *m;
Handler() {m=new Model;cout<<"Handler constructor called"<<endl;}
Handler(const Handler& h)
{
std::cout << "Inside Handler @lineNumber:" << __LINE__ << std::endl;
i=h.i;
m=new Model(*h.m);
}
Handler(int val):i(val) {}
~Handler() {delete m;}
void hi() {cout<<"Value of i="<<i<<endl;}
int getI() {return i;}
void setI(int j) {i=j;}
int getX() {return m->getX();}
void setX(int xx) {m->setX(xx);}
};
class ControlPanel
{
public:
int abc;
Vir *v;
ControlPanel(const ControlPanel& c)//copy constructor
{
std::cout << "Inside ControlPanel @lineNumber:" << __LINE__ << std::endl;
v=new Handler((Handler&)*(c.v));
}
void initialize() {v=new Handler();v->setI(10);abc=222;}
void hi() {v->hi();}
ControlPanel() {}
~ControlPanel() {delete v;}
};
int main()
{
ControlPanel cc;
cc.initialize();
cc.hi();
cout << "(cc.v)->i::" << (cc.v)->getI() << endl;
cout<<"x value cc="<<(cc.v)->getX()<<endl;
ControlPanel bb(cc);//copying cc into bb
cout << "(bb.v)->i::" << (bb.v)->getI() << endl;
cout<<"x value bb="<<(bb.v)->getX()<<endl;
(cc.v)->setI(999);
(cc.v)->setX(888888888);
cout << "(cc.v)->i::" << (cc.v)->getI() << endl;
cout << "(bb.v)->i::" << (bb.v)->getI() << endl;
cout<<"x value cc="<<(cc.v)->getX()<<endl;
cout<<"x value bb="<<(bb.v)->getX()<<endl;
}//main
/*
Output:
Model constructor called
Handler constructor called
Value of i=10
(cc.v)->i::10
x value cc=555
Inside ControlPanel @lineNumber:52
Inside Handler @lineNumber:32
(bb.v)->i::10
x value bb=555
(cc.v)->i::999
(bb.v)->i::10
x value cc=888888888
x value bb=555 */