2016-11-10 208 views
1

想象一下,我有一个Base类和两个派生自它的类One和Two。在Java中,我可以有以下情形:在C++中实例化派生类型

Base b; 
if(condition) 
    b = new One(); 
else 
    b = new Two(); 

在对象类型在运行时确定(上述目的去堆)。我希望能够在运行时实例化对象类型 - 我所知道的是它们都共享相同的Base类型 - 但我想保留它的堆栈分配,如下所示:

Base b; 

这样做的最好方法是什么?

+1

删除记忆 - 有没有(Java不分配堆栈上的对象,所以这2例是不相同)。即使你可以,你的对象也会被[切片](http://stackoverflow.com/questions/274626/what-is-object-slicing)为“Base”类型。 –

+1

你不能(以任何通知可维护的方式)。它是堆栈分配的,所以它的大小必须在分配时已知。记住在Java中你的对象不是堆栈分配的,所以虽然用C++编写的Java代码暗含了堆栈分配,但并不意味着在Java中。 – djgandy

+0

这是经典的XY问题 - http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Slava

回答

1

这样做的最好方法是什么?

你不行。如果你声明一个变量类型为Base,那么它的堆栈分配将适用于持有Base的实例,但不适用于派生类型的实例(它可能较大,尽管不是,但仍不能完成你的任务问; C++中的变量的运行时类型始终与其声明的类型相同)。充其量,您可以将slice派生实例转换为Base-类型的变量。

最好的选择是使用一个指针,可选地包装在shared_ptrunique_ptr中给你类似的语义。假定所有权没有被转移时,该对象在超出范围时自动销毁)。

Base* b = (condition) ? (Base *) new One() : new Two(); 
auto bptr = shared_ptr<Base>(b); 

注意,这是什么让你实际上是一样的Java。对象本身是堆分配的,但是对它的引用是堆栈分配的。尽管有语法,但引用类型的Java变量本质上等同于C++中的指针。

-1

为了在C++中使用继承,您需要定义一个指针而不是静态对象,然后使用new关键字对其进行实例化。

实施例:

Base* b; 
if(condition) 
    b = new One(); 
else 
    b = new Two(); 
0

采取的,例如:

Derived d; 
Base* b = &d; 

d是堆栈(自动存储器)上,但仍然多态性将在b工作。

如果您没有基类指针或对派生类的引用,则多态性不起作用,因为您不再具有派生类。就拿

Base c = Derived(); 

c对象不是Derived,但Base,因为切片。因此,从技术上讲,多态性仍然有效,只不过你不再有一个对象来谈论。

现在采取

Base* c = new Derived(); 

c只是指向内存的某个地方,你真的不关心这是否是实际上是一个BaseDerived,但调用的virtual方法将被动态解析。

所以,看起来,与Java不同,没有堆分配或指针方式,没有办法实现动态绑定。

0

正如评论说你不能。嗯,你可以但不会运行:

Base &b = *(condition ? (Base *)&One() : (Base *)&Two()); // BROKEN CODE DO NOT USE 

(构建使用-fpermissive,但不这样做!)

因为One & Two对象是临时对象。 b一旦你通过下一行就会无效=>不这样做(不知道我已经说过了)

以下工作,但不完美:在堆栈上构建两个对象,所以只有在你可以负担得起。根据条件只要选择:

One one; 
Two two; 
Base &b = *(condition ? (Base *)&one : (Base *)&two); 

为了避免双重分配,我能想到的在使用方面最接近的事是采取分配的对象的引用(还没有自动变量,不好意思):

Base &b = *(condition ? (Base *)new One() : (Base *)new Two()); 

因此,您可以在代码中使用b作为Base

你还有如果你想成为堆栈中分配你的对象与

delete (&b); 
+0

对不起,我没有测试过的唯一代码:)修复。 –