是否总是需要从堆中分配内存以促进动态多态?到目前为止我遇到的所有例子都指向相同的例子。 在实时编程中通常可以避免动态内存分配。因此,使用堆栈进行动态多态性是否有任何缺点,如下面的代码所示。
class Base
{
public:
virtual void Display()= 0;
};
class Derived:public Base
{
public:
void Display()
{
cout << "In derived" << endl;
}
};
int main()
{
Base* base;
Derived derived1;
base = &derived1;
base->Foo();
return 0;
}
答案 0 :(得分:7)
更好的例子是:
void func(Base &base);
int main()
{
Derived derived;
func(derived);
return 0;
}
多态性的使用不必靠近堆栈上创建对象的位置。
现在我们的许多单元测试代码大致如下:
void test()
{
MockObject mockObj;
RealObject objectToBeTested(mockObj);
// Do tests
}
这很大程度上取决于多态性,但会在堆栈上创建对象。
答案 1 :(得分:4)
如果你想要使用多态,你没有拥有来使用堆,正如你在问题中指出的那样。但是你经常别无选择。小做作的例子:
void doSomething(int what) {
// figure out which implementation to create
Base * b;
if(doA) {
b = new ConcreteA; // 1a
} else if(doB) {
b = new ConcreteB; // 1b
}
...
b->...; // 2
}
您不能使用堆栈,因为目前您知道该怎么做,1a和1b,当您再次留下该范围时,您将从堆栈中获取的每个存储都将被回收。您必须使用堆,因为您需要一些持续该局部范围的存储。
有些图书馆宣传他们不能使用堆,但仍然表现出多态性。他们通常使用新的位置来做到这一点:
void doSomething(int what) {
// allocate form *the stack*, outside the if blocks, so this
// storage lasts until the function returns
char buffer[MAX(sizeof (ConcreteA), sizeof(ConcreteB))];
if(doA) {
new (buffer) ConcreteA; // 1a
} else if(doB) {
new (buffer) ConcreteB; // 1b
}
Base *b = static_cast<Base*>(static_cast<void*>(buffer));
b->...; // 2
}
1a和1b中的新调用现在使用堆栈上创建的缓冲区作为创建对象的存储。因此,不再需要堆内存分配。这种形式的分配有一个主要的缺点,即在C ++中目前不可能判断缓冲区是否为ConcreteA和ConcreteB类型正确对齐。因此,可能是数组在2字节边界上对齐,但是需要在4字节边界上创建对象,当您尝试将这些对象创建到该缓冲区时会导致未定义的行为。
Boost.Function是那些使用这种放置新方法来创建多态类型对象而不使用小缓冲区使用堆分配的库之一(因此,它所做的就是称为小缓冲区优化 )。
答案 2 :(得分:0)
我认为这很好。唯一可能的缺点是在堆栈上创建的对象的范围有限,但这不一定与多态性有关。
答案 3 :(得分:0)
使用堆栈没有问题。
当您使用堆栈时,您通常会确切地知道它是什么类型的对象...因此不需要该方法是虚拟的,它是无害的,但不必要,例如:
Derived derived;
derived.Foo();
但是,对象(存在于堆栈中)可以传递给子程序,该子程序接受超类实例作为参数(在这种情况下,它是子类的实用/使用的事实):
void foo(Base* base)
{
...
}
void test()
{
Derived derived;
foo(&derived);
}
答案 4 :(得分:0)
对于您展示的简单案例,使用堆栈会很好。动态多态与静态的一个实时问题是经过方法调用间接的额外时间。这是每个方法调用的额外内存访问。
您需要详细说明您在分析其他因素方面所做的工作,例如:是保证在物理内存中的堆栈帧,共享,实例数,实例的生命周期