来自类实例的派生类?

时间:2013-04-04 08:42:56

标签: c++ inheritance

如何创建一个可以从其基类实例中更改所有变量的派生类?我理解我可以声明基类变量是静态的,但是当我这样做时,我无法使用函数初始化它们,这使得代码非常消息并且难以编辑。

这是一个示例类;为什么c2不能在theC1类中编辑x。如果它引用的是不是C1的c1类,那么引用的是什么?

#include <stdio.h>

class c1
{
public:
    c1( int d )
    {
        x = d;
    }
    int x;
};

class c2 : public c1
{
public:
    c2( c1& ref )
        :
    c1( ref )
    {};
    void setx()
    {
        x = 5;
    }
};

int main () 
{
    c1 theC1(4);
    c2 theC2(theC1);
    theC2.setx();

    printf( "%d\n",theC1.x );
    printf( "%d\n",theC2.x );

    return 0;
}

2 个答案:

答案 0 :(得分:2)

您正在使用引用来调用c1的复制构造函数,而不是保存对c1对象的引用。你想要这样的东西:

class c2 : public c1
{
public:
    c2( c1& ref )
        : c1_ptr(&ref) {}

    void setx()
    {
        c1_ptr->x = 5;
        this->x   = 5;
    }
private:
    c1 * c1_ptr;
};

但是,这需要c1的默认构造函数。如果您根本不需要任何构造,则可能需要使用代理类:

class c1_proxy
{
public:
    c1_proxy( c1& ref )
        : x(ref.x), c1_ptr(&ref) {}

    void setx()
    {
        c1_ptr->x = 5;        
    }
    int & x;
private:
    c1 * c1_ptr;
};

但是,我认为这是反模式。请注意,您必须手动更新所有值。

答案 1 :(得分:1)

theC1theC2是完全独立的实例。 theC2包含c1类型的子对象,该对象由引用ref初始化,但它仍然(并且将始终是)c1的不同实例而不是theC1 }。基类子对象是每个c2实例的成员,并且无法与c2c1的任何其他实例“共享”。

您可以将引用存储在c2中并访问该引用,而不是从c1派生,如果这是您所追求的语义。代码将如下所示:

class c1
{
public:
    c1( int d )
    {
        x = d;
    }
    int x;
};

class c2
{
    c1 &myC1;
public:
    c2( c1& ref )
        :
    myC1(ref)
    , x(myC1.x)
    {}
    void setx()
    {
        myC1.x = 5;
    }
    int &x;
};

当然,最好将x封装起来,而不是将其公开,并且必须使用上面代码中的参考技巧。

<强>更新

更大规模实施此方法的一种方法可能是c1c2实现相同的界面,c2个实例共享c1的“数据实例”:

#include <memory>


struct c1_iface
{
  virtual int getX() const = 0;
  virtual void setX(int newX) = 0;
};


class c1 : public c1_iface
{
  int x;

public:
  virtual int getX() const { return x; }
  virtual void setX(int newX) { x = newX; }
};


class c2 : public c1_iface
{
  std::shared_ptr<c1> data_;

public:
  explicit c2(std::shared_ptr<c1> data) : data_(data) {}

  virtual int getX() const { return data_->getX(); }
  virtual void setX(int newX) { data_->setX(newX); }
};

如果您无法访问C ++ 11,则可以使用boost::shared_ptr代替(或者仅使用手动共享,而不是真正推荐)。

作为一个稍微脏一点的替代方法,您可以将共享指针(或其等价物)移动到c1_iface并使函数非抽象,解除引用。