喂,
我来自C#背景,并且没有很多C ++经验。为了生成干净的代码,我尝试将实现和接口分开并尽可能使用继承。当我尝试将典型的C#概念应用于C ++时,我遇到了一个迄今为止我无法解决的问题。我认为对于经验丰富的C ++程序员来说这可能是微不足道的,但它已经让我疯了很长一段时间。
首先,我声明一个基类(目前它不包含逻辑,但将来会包含它)
class PropertyBase : public IProperty
{
};
然后我为Properties
定义了一个接口class IProperty
{
public:
virtual ~IProperty() {};
virtual PropertyBase correct(const ICorrector &corrector) = 0;
virtual PropertyBase joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};
这就是问题所在:编译器返回两个虚函数的错误,说明不允许声明一个返回抽象类的函数。当然我不想返回PropertyBase
类型的对象。我想声明从PropertyBase
继承的其他类返回自己的实例。
现在我已经读过可能的方法是修改IProperty
这样的返回指针:
class IProperty
{
public:
virtual ~IProperty() {};
virtual PropertyBase* correct(const ICorrector &corrector) = 0;
virtual PropertyBase* joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};
但是,如果可能的话,我想避免这种情况,以防止内存泄漏。如果有人能够更好地处理这个问题,那将会很棒。
非常感谢
答案 0 :(得分:5)
如果您害怕内存泄漏,请切换到智能指针。这具有自我记录的额外好处。所返回对象的所有权。
class IProperty
{
public:
virtual ~IProperty() {};
virtual std::unique_ptr<PropertyBase> correct(const ICorrector &) = 0;
virtual std::unique_ptr<PropertyBase> joinWith(const PropertyBase &,
const IRecombinator &) = 0;
};
在您的客户端代码中:
std::unique_ptr<PropertyBase> pb(property.correct(corrector));
// use pb and forget about it; smart pointers do their own cleanup
或者,如果你想在对象上引用计数:
std::shared_ptr<PropertyBase> pb(property.correct(corrector));
请参阅unique_ptr
,shared_ptr
的MSDN文档。
答案 1 :(得分:2)
这可能不是您正在寻找的答案,但在我看来,您对C ++中的指针和值有点困惑。
如果你想要适当的ad-hoc多态,你必须在C ++中返回一个指针或一个引用。在这种情况下,编译器发出错误,因为基类是抽象的。如果可以实例化一个抽象类,那么它就会有“漏洞”。
拇指规则是:只要有类层次结构,就不要按值返回此类类型的对象。假设您有class Base { int x; }
和class Derived : public Base { int y; }
。如果你这样做:
Base Function() { Derived d; return d; }
...
Base b = Function();
然后b
将不会隐藏在“Derived
后面的Base
类的值”。值b
将为Base
。编译器将“切掉”Derived
和Base
之间的差异,并将其放入b
。
在C ++中,您必须使用指针或引用来促进ad-hoc多态。 C#中的引用与C ++中的指针几乎完全相同,除了你不必释放C#中的对象,因为垃圾收集器会为你处理这个。
答案 2 :(得分:0)
返回指向对象的指针没有错。如果您担心内存泄漏,就像您应该的那样,解决方案是使用智能指针来存储返回的指针。其中最灵活的是来自boost的shared_ptr
或即将推出的C ++ 0x标准。
答案 3 :(得分:0)
更一般地说,如果你要在C ++中做大量的工作,那么掌握指针和内存管理是很重要的。为了深入介绍C ++的这些以及其他棘手的方面,我强烈推荐Scott Meyers撰写的 Effective C ++ 书籍和Herb Sutter撰写的 Exceptional C ++ 书籍。
答案 4 :(得分:0)
这个问题很容易解决。使用指针或引用作为返回值,但不应返回指针中的所有权,而是不应返回所有权。
例如:
class A : public Base
{
public:
Base *correct(const I &c)
{ p2 = do_something(c); return &p2; }
...
private:
A2 p2;
};
使这项工作的原因是您将p2存储在类中,并且永远不会将对象的所有权传递给它外部。界面中的函数将不创建新对象,而是只返回现有的对象,配置为根据函数的参数更正状态。这是unique_ptr和shared_ptr解决方案的一个很好的替代方案,它依赖于堆分配并创建新对象并传递它们。
现在这个很好的技巧是你需要在类的数据成员中列出要从正确的()函数返回的所有可能的类型。例如,如果有时你会返回不同的类型,它看起来像这样:
class B : public Base
{
public:
Base *correct(const I &c) {
switch(c.get_bool()) {
case false: p3 = do_something_else(c); return &p3;
case true: p4 = do_something(c); return &p4;
};
}
private:
B3 p3;
B4 p4;
};
但是将对象p3和p4放在当前B对象中将完全解决这个问题。