2

私の目的は、クラスのディープ コピーを作成することですが、仮想クラスが問題を引き起こしています。

#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’

Vir から継承し、独自のメンバー (float a; や double b; など) を持つ Handler クラス (Handler1、Handler2 など) をさらにたくさん用意する予定です。したがって、すべての Handler クラスのすべての getter および setter 関数を Vir クラスに保持することは意味がありません。メンバーは Handler クラスに固有であるため、getter メソッドと setter メソッドを Handler クラスに保持したいと考えています。コンパイラは私にそうすることを許可していません。ヘルプ?

4

6 に答える 6

2

たぶん私は何かが欠けているかもしれませんが、仮想cloneメソッドをオンにしたほうがいいのではないでしょうVirか? ControlPanelこれは、独自の回答で概説されているコピー コンストラクターで厄介なキャストを回避できることを意味します。これは、@Andrew Aylett が彼の回答duplicateの代わりに使用されていることを示唆しているものと同じですclone

何かのようなもの

class Vir
{
    public:
    virtual Vir* clone() const = 0;
    ...
};

実装さHandlerれる

Handler* Handler::clone() const
{
    return new Handler( *this );
}

共変の戻り値の型の使用に注意してください。つまり、単なる a ではなくHandler::clonea を返すことが許可されており、それでも の有効なオーバーライドになります。Handler*Vir*Vir::clone

これにより、ControlPanelコピーコンストラクターが単純になります

ControlPanel( const ControlPanel& c )
    : v( c.v->clone() )
{
}
于 2010-10-01T12:48:05.327 に答える
2

抽象クラスに関数を追加duplicate()します。これにより、(各派生クラスで) 正しい値を持つ新しいインスタンスが作成され、それが返されます。copyFrom(Abs other)または、正しいタイプからコピーしていることを確認し、正しい場合はフィールドをコピーする関数を検討してください。

一般に、ControlPanel クラスが Abs オブジェクトへの参照を持っている場合、具体的な Handler オブジェクトを調べてその複製を行うべきではなく、そのオブジェクトの仮想関数に複製を渡す必要があります。

于 2010-09-30T09:38:34.983 に答える
0

なぜコンパイラはあなたを許可するのでしょうか?それらのメソッドはそのインターフェース上にありません。

ファクトリパターンを使用してを作成Virし、すべてのコンストラクタをVirのインターフェイスに追加する必要をなくすことができます。また、initialize()スタイルの関数を回避するためにRAIIの使用を検討する必要があります。

于 2010-09-28T14:54:21.083 に答える
0

に変更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;
};
于 2010-09-28T14:54:52.670 に答える
0

サブクラスを介してアクセスできるようにするには、(純粋な)仮想として定義する必要がありgetIます。これを回避する方法はありません。setIVir

于 2010-09-28T14:55:56.213 に答える
0

スティーブが示唆したように、友人が解決策を教えてくれたので、私は自分の質問に答えています。仮想クラスが障害になる可能性がある 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  */
于 2010-10-01T12:11:35.433 に答える