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 继承的 Handler 类(如 Handler1、Handler2 等),并将拥有自己独特的成员(如 float a; 或 double b; 等)。因此,将所有 Handler 类的所有 getter 和 setter 函数保留在 Vir 类中对我来说是没有意义的。我想在 Handler 类中保留我的 getter 和 setter 方法,因为这些成员对于 Handler 类是唯一的。编译器不允许我这样做。帮助?

4

6 回答 6

2

向您的抽象类添加一个duplicate()函数,该函数(在每个派生类中)创建一个具有正确值的新实例并返回它。或者,考虑一个copyFrom(Abs other)检查以确保您从正确的类型复制的函数,如果是,则复制字段。

通常,如果您的 ControlPanel 类引用了 Abs 对象,则不应尝试通过检查具体的 Handler 对象来进行复制,而应将复制传递给该对象上的虚函数。

于 2010-09-30T09:38:34.983 回答
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 );
}

请注意协变返回类型的使用,即Handler::clone允许返回 aHandler*而不仅仅是 aVir*并且仍然是Vir::clone.

这使得ControlPanel复制构造函数变得简单

ControlPanel( const ControlPanel& c )
    : v( c.v->clone() )
{
}
于 2010-10-01T12:48:05.327 回答
0

为什么编译器会允许你?这些方法不在该接口上。

您可以使用工厂模式来创建您的Vir, 以避免将所有构造函数添加到Vir的接口。您还应该考虑使用RAII来避免使用 initialize() 样式函数。

于 2010-09-28T14:54:21.083 回答
0

更改Vir *vHandler *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

您必须将getIand定义setI为(纯)virtual inVir以使它们可以通过子类访问。没有办法解决这个问题。

于 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 回答