我正在努力克服C ++中看似简单的任务。我试图实现基本的OOP多态性。
考虑这个Java示例:
interface Bob
{
void foo();
}
class ActualBob implements Bob
{
void foo()
{
/* I like foo things */
}
}
class Jane
{
Bob bob;
}
Jane可以拥有任何Bob,轻松:
Jane jane = new Jane();
jane.bob = new ActualBob();
jane.bob.foo(); // actualbob things
现在,在C ++中,这似乎有点涉及...... 为了获得上述行为,我需要输入什么内容?
换句话说,我想拥有一个抽象基类的成员变量,但是想用它们做实际的实现。
class Bob
{
public:
virtual void foo() = 0;
}
class ActualBob : public Bob
{
public:
void foo(){/* I like foo things */}
}
class Jane
{
public:
Bob bob;
}
在这里采取捷径,但我想在C ++中做:
jane.bob.foo(); // does ActualBob things
另外,我可以拥有包含std::vector<Bob>
个实例的ActualBob
吗?
答案 0 :(得分:6)
使用指针,智能指针,如下所示:
class Bob
{
public:
virtual void foo() = 0;
}
class ActualBob : public Bob
{
public:
void foo() override {/* I like foo things */}
}
class Jane
{
public:
std::unique_ptr<Bob> bob;
}
在这里采取捷径,但我想用C ++做:
jane.bob.foo(); // does ActualBob things
你可以这样做:
jane.bob->foo(); // does ActualBob things, if `bob` is a pointer to ActualBob
另外,我可以拥有包含
std::vector<Bob>
个实例的ActualBob
吗?
是的,经过一些修改后,您可以拥有std::vector<Bob*>
(但您必须自己释放内存),或者更好的是一些智能指针,例如std::vector<std::unique_ptr<Bob>>
。
答案 1 :(得分:1)
如果Bob
是非多态的,那么您的代码就可以了:
class Jane
{
public:
Bob bob;
};
但是,尝试在bob
中存储多态对象会导致对象切片,这会丢弃多态性。为了保留它,请使用指针或对Bob
的引用。
根据Bob
的所有权,您可以使用不同类型的指针,甚至是引用。例如,如果Bob
是动态分配的,并且可以在Jane
的多个实例之间共享,则使用std::shared_ptr<Bob>
是合适的:
class Jane
{
public:
Jane(Bob* bPtr) : bob(bPtr) {}
std::shared_ptr<Bob> bob;
};
答案 2 :(得分:1)
你几乎拥有它。问题是,在Java中似乎不必使用任何东西来创建多态对象,而实际上在Java中所有变量都是引用。 Java引用是具有较少功能的C ++指针。
在C ++中,当您键入Bob bob;
时,您实际上是在左侧创建精确类型的对象。当你使用指针代替时,在右边你可以有一个 Bob 对象(在这种情况下这是不可能的,因为类 Bob 有一个纯虚方法)或任何其他子类。
所以,在你的代码中:
class Jane
{
public:
Jane()
{ bob = new ActualBob(); }
Bob * bob;
}
但是,我们在没有任何警告的情况下遇到了另一种危险的情况。 Java有一个垃圾收集器,基本上意味着删除了任何未引用的对象。这不是在C ++中自动完成的,因此我们必须使用delete
运算符手动完成。或者在这种情况下可能是智能指针:它们在C ++中表现自动删除对象。我们有std::unique_ptr<>
可用,正是这样做的。确实存在其他方案,例如复制 Jane 对象,这些对象在某种程度上由智能指针管理。因此,不要谈论rules(析构函数,复制构造函数,运算符赋值和族),而是使用其中一个:
class Jane
{
public:
Jane()
{ bob.reset( new ActualBob() ); }
unique_ptr<Bob> bob;
}
unique_ptr<>
智能指针捕获->
的使用(从技术上讲,它有箭头运算符重载),因此在语法上使用常规指针非常熟悉。现在:
Jane jane = new Jane();
jane.bob->foo();
另外,我可以拥有包含ActualBob的
std::vector<Bob>
吗? 实例
当然,但必须以与上面相同的方式更改代码:您必须使用std::vector<Bob *>
,并自行释放成员指向的对象。或者,您可以再次使用智能指针,如:std::vector<unique_ptr<Bob>>
。
希望这有帮助。