来自类实例的派生类?
我该如何制作一个派生类,它可以改变其基类实例的所有变量?我知道我可以声明基类变量是静态的,但是当我这样做时,我无法使用函数初始化它们,这使得代码非常消息且难以编辑。来自类实例的派生类?
这是一个示例类;为什么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;
}
theC1
和theC2
是完全独立的实例。 theC2
包含c1
类型的子对象,该对象由参考号ref
初始化,但它仍然(并且总是)将是c1
的另一个实例,而不是theC1
。基类子对象是每个c2
实例的成员,并且无法与其他任何c2
或c1
的实例“共享”。
如果那是您之后的语义,您可以将引用存储在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
一种方式来实现这在更大的范围可能是c1
和c2
实现相同的接口,并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
中,并使函数非抽象,对其进行解引用。
感谢您的帮助。这就是我想要做的事情,除了一点清洁剂。如果在基类实例中没有派生类共享变量的方法,那么让大量类访问类c1实例的变量的最佳方法是什么? – joelyboy94 2013-04-04 11:20:30
@ joelyboy94我已经扩大了答案。 – Angew 2013-04-04 11:42:12
您使用的参考调用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;
};
不过,我认为这是一个反模式。请注意,您必须手动更新所有值。
嗨,谢谢你的回答。我试过,但它说c1没有默认的构造函数。问题是我不想构造一个c1,我只想引用或指向一个c1的实例。 – joelyboy94 2013-04-04 08:51:51
@ user2243911:这可能发生是因为我没有调用'c1'的正确构造函数,请参阅Angew的答案。如果你不想构建'c1',你不应该继承它。 – Zeta 2013-04-04 08:56:11
这甚至不应该编译......或者至少要给出大量的警告。 – fredrik 2013-04-04 08:45:12
@fredrik嗯,为什么? – Angew 2013-04-04 08:51:12
@fredrik:其实它是完全有效的。这不是很好,它包含C头文件,但它是完全有效的,并且将在没有任何错误或警告的情况下进行编译。 – Zeta 2013-04-04 08:51:25