我有一个C ++切片问题。我是C ++的新手,所以也许只是太愚蠢而无法实现这一点......我尝试了各种各样的解决方法,而我目前的最佳方法如下所示。 (我需要做这样的事情,以避免在一个非常大的遗留代码库中改变大量的接口。不要声称这是一种优雅的风格!)
编译时遇到麻烦。这个想法听起来好吗?或整个方法注定要失败?引用的构造函数似乎是问题。我读过Stroustrup的“C ++ Programming Lanugage”(或者至少我认为是相关部分),但它没有帮助。
class FOO {};
class FOOSUBCLASS : public FOO {
public:
FOOSUBCLASS(const int id = 0) : _id(id) {}
private:
int _id;
};
class BAR {
public:
BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }
BAR(const FOOSUBCLASS foosc) : _foosc(foosc), _realFoo(&_foosc) {}
private:
FOO _foo;
FOOSUBCLASS _foosc;
FOO& _realFoo;
};
编译器不喜欢我的_realFoo(&_foo)
行。我想引用_foo
,只是来自类中成员变量的引用。这在C ++中是不可能的吗?
以下是VS2005的具体错误:
'initializing' : cannot convert from 'FOO *' to 'FOO &'
答案 0 :(得分:2)
_foo
是FOO&
&_foo
是FOO*
编译器cannot convert from 'FOO *' to 'FOO &'
。
你想要的是..., _realFoo(_foo)
无关:您可能真正想要的是std::unique_ptr<FOO>
成员。这将更小,更不容易出错。
现在拥有的结构包含FOO
的完整实例,以及FOOSUBCLASS
的完整实例和引用。在至少将两个FOO
内容放在一个联合中,因此BAR
的大小仅比最大FOO
衍生物略大。这可能会使用与unique_ptr<FOO>
相同的内存。不幸的是,union
是C和C ++中常见的错误来源。
另一个问题是,如果有人出现并写作
class FOOSOMETHINGELSE : public FOO {
int buffer[1024];
};
然后你必须去查找BAR
类并更改它并使其更大,并重新编译所有使用BAR
的代码。然而,如果您使用unique_ptr<FOO>
,那么您将不必更改BAR
或重新编译任何内容。因此错误的可能性较小。
答案 1 :(得分:1)
这里有几个问题。你正确地将它们中的一个识别为切片,但切片不会导致编译时错误(这使得它如此可怕......)。 Mooing Duck的答案应该解决你所遇到的编译问题,但切片问题仍然存在。假设你有
FOO *x = new FOOSUBCLASS;
BAR y(*x);
这将导致切片,因为将调用以下构造函数:
BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }
并且它通过值获取其参数,意味着将从派生到基础的副本发生。
当您尝试将派生类类型的对象分配给基类对象时发生切片,例如,通过将派生类传递给一个函数,该函数在此处执行基类按值。基本上,派生类对象的任何数据成员都会静默地“切掉”,因为根本没有任何空间可以将它们放在一块只能容纳基类对象的内存中。当您需要使用实际可能属于派生类的对象时,必须使用引用指针(或shared_ptr
或unique_ptr
等智能指针)。
我很确定你想要做的就是让一个BAR
对象引用一个FOO
对象或从它派生的对象 - 对吗?在这种情况下(假设FOO
对象的生命周期超过BAR
对象的生命周期),您只需要:
class BAR {
public:
explicit BAR(FOO& foo) : _foo(foo) {}
private:
FOO& _foo;
};