如果不在纯虚拟基类中创建显式函数,就无法完成复制构造吗?

发布于 2024-09-25 09:46:27 字数 1404 浏览 7 评论 0原文

我的目标是对一个类进行深度复制,但虚拟类造成了麻烦。

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

我计划有更多的 Handler 类(如 Handler1、Handler2 等),它们继承自 Vir,并将有自己独特的成员(如 float a; 或 double b; 等)。所以对我来说保留所有的吸气剂和吸气剂是没有意义的。 Vir 类中所有 Handler 类的 setter 函数。我想将 getter 和 setter 方法保留在 Handler 类中,因为这些成员对于 Handler 类来说是唯一的。 编译器不允许我这样做。帮助?

My objective is to do a deep copy of a class, but a virtual class is causing trouble.

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

The compilation error message:

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’

I plan to have plenty more Handler classes (like Handler1, Handler2 etc) which inherit from Vir and will have their own unique members (like float a; or double b; etc). So it doesn't make sense for me to keep all the getter & setter functions of all Handler classes in the Vir class. I want to keep my getter and setter methods in the Handler classes because the members are unique to the Handler classes.
The compiler is not allowing me to do so. Help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

扭转时空 2024-10-02 09:46:27

也许我遗漏了一些东西,但是在 Vir 上使用虚拟 clone 方法不是更好吗?这意味着您可以避免在您自己的答案中概述的 ControlPanel 复制构造函数中进行令人讨厌的转换。这与 @Andrew Aylett 在 他的答案使用了重复而不是克隆

Handler中实现的类似的东西

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

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

注意协变返回类型的使用,即Handler::clone允许返回一个Handler*而不仅仅是一个 Vir* 并且仍然是 Vir::clone 的有效覆盖。

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

ControlPanel( const ControlPanel& c )
    : v( c.v->clone() )
{
}

Maybe I am missing something but would you not be better with a virtual clone method on Vir? This means you can avoid the nasty cast in the ControlPanel copy constructor outlined in your own answer. This is the same as @Andrew Aylett suggests in his answer with duplicate being used instead of clone.

Something like

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

which is implemented in Handler to be

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

Note the use of the covariant return type i.e. Handler::clone is allowed to return a Handler* rather than just a Vir* and still be a valid override of Vir::clone.

This makes the ControlPanel copy constructor simply

ControlPanel( const ControlPanel& c )
    : v( c.v->clone() )
{
}
饮惑 2024-10-02 09:46:27

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

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

Add a duplicate() function to your abstract class, which (in each derived class) creates a new instance with the right values and returns it. Alternatively, consider a copyFrom(Abs other) function which checks to ensure that you're copying from the correct type and if so, copies the fields out.

In general, if your ControlPanel class has a reference to an Abs object, it shouldn't be trying to do its duplication by inspecting the concrete Handler object, it should be passing the duplication off to a virtual function on that object.

简单爱 2024-10-02 09:46:27

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

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

Why would the compiler allow you? Those methods are not on that interface.

You could use the Factory Pattern to create your Vir, to avoid having to add all of the constructors to Vir's interface. You should also consider using RAII to avoid initialize() style functions.

祁梦 2024-10-02 09:46:27

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;
};

Change Vir *v to Handler *v; and see whether your code compiles or not.

Your class Vir doesn't declare/define setI() and getI() member functions.

Or define Vir as

class Vir//pure virtual class
{
    public:
    virtual void hi()=0;
    virtual int getI()const =0;
    virtual void setI(int)=0;
};
你的心境我的脸 2024-10-02 09:46:27

您必须在 Vir 中将 getIsetI 定义为(纯)虚拟,以使它们可以通过子类访问。没有办法解决这个问题。

You have to define getI and setI as (pure) virtual in Vir to make them accessible via subclasses. No way around this.

﹉夏雨初晴づ 2024-10-02 09:46:27

正如史蒂夫所建议的,我正在回答我自己的问题,因为一位朋友给了我一个解决方案。希望这对任何有如何在 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  */

As Steve suggested, I'm answering my own question coz a friend gave me a solution. Hope this would be of help to anyone who has the question of how to do a Deep copy in C++ where a virtual class may be a roadblock. Hope someone finds this useful.

#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  */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文