2013-04-04 124 views
0

我该如何制作一个派生类,它可以改变其基类实例的所有变量?我知道我可以声明基类变量是静态的,但是当我这样做时,我无法使用函数初始化它们,这使得代码非常消息且难以编辑。来自类实例的派生类?

这是一个示例类;为什么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; 
} 
+1

这甚至不应该编译......或者至少要给出大量的警告。 – fredrik 2013-04-04 08:45:12

+0

@fredrik嗯,为什么? – Angew 2013-04-04 08:51:12

+1

@fredrik:其实它是完全有效的。这不是很好,它包含C头文件,但它是完全有效的,并且将在没有任何错误或警告的情况下进行编译。 – Zeta 2013-04-04 08:51:25

回答

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,而不是把它公开,并不得不诉诸引用的技巧,比如那些在上面的代码。

UPDATE

一种方式来实现这在更大的范围可能是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中,并使函数非抽象,对其进行解引用。

+0

感谢您的帮助。这就是我想要做的事情,除了一点清洁剂。如果在基类实例中没有派生类共享变量的方法,那么让大量类访问类c1实例的变量的最佳方法是什么? – joelyboy94 2013-04-04 11:20:30

+0

@ joelyboy94我已经扩大了答案。 – Angew 2013-04-04 11:42:12

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

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

+0

嗨,谢谢你的回答。我试过,但它说c1没有默认的构造函数。问题是我不想构造一个c1,我只想引用或指向一个c1的实例。 – joelyboy94 2013-04-04 08:51:51

+0

@ user2243911:这可能发生是因为我没有调用'c1'的正确构造函数,请参阅Angew的答案。如果你不想构建'c1',你不应该继承它。 – Zeta 2013-04-04 08:56:11