不能创建多态局部变量
您不能创建多态局部变量,因为A 的子类B 可能具有比A 更多的属性,因此占用更多空间,因此编译器必须为最大的子类保留足够的空间A.
- 如果你有几十个子类,其中一个有大量属性,这会浪费很多空间。
- 如果您将接收到的
A 子类的实例作为参数放入局部变量中,并且您将代码放入动态库中,那么与其链接的代码可以声明一个大于你的库,所以编译器无论如何都不会在堆栈上分配足够的空间。
所以自己给它分配空间
使用placement new,您可以通过其他方式在您分配的空间中初始化对象:
但是,这些技术可能会占用大量额外空间,并且如果您获得的引用(指针)指向 A 的未知编译时子类,且该子类大于您所使用的类型,则这些技术可能无法使用占了。
我建议的解决方案是在每个子类上都有一种工厂方法,它调用一个提供的函数,该函数带有一个指向给定子类的堆栈分配实例的指针。我在提供的函数的签名中添加了一个额外的 void* 参数,因此可以将任意数据传递给它。
@MooingDuck 在下面的评论中建议 this implementation 使用模板和 C++11。如果您需要它用于无法从 C++11 功能中受益的代码,或者对于一些带有结构而不是类的普通 C 代码(如果 struct B 具有 struct A 类型的第一个字段,则可以对其进行操作有点像A 的“子结构”),那么我下面的版本就可以解决问题(但不是类型安全的)。
这个版本适用于新定义的子类,只要它们实现ugly类工厂方法,并且它将使用一个恒定数量的堆栈用于返回地址和该中间函数所需的其他信息,加上大小所请求类的实例的大小,但不是最大子类的大小(除非您选择使用那个)。
#include <iostream>
class A {
public:
int fieldA;
static void* ugly(void* (*f)(A*, void*), void* param) {
A instance;
return f(&instance, param);
}
// ...
};
class B : public A {
public:
int fieldB;
static void* ugly(void* (*f)(A*, void*), void* param) {
B instance;
return f(&instance, param);
}
// ...
};
class C : public B {
public:
int fieldC;
static void* ugly(void* (*f)(A*, void*), void* param) {
C instance;
return f(&instance, param);
}
// ...
};
void* doWork(A* abc, void* param) {
abc->fieldA = (int)param;
if ((int)param == 4) {
((C*)abc)->fieldC++;
}
return (void*)abc->fieldA;
}
void* otherWork(A* abc, void* param) {
// Do something with abc
return (void*)(((int)param)/2);
}
int main() {
std::cout << (int)A::ugly(doWork, (void*)3);
std::cout << (int)B::ugly(doWork, (void*)1);
std::cout << (int)C::ugly(doWork, (void*)4);
std::cout << (int)A::ugly(otherWork, (void*)2);
std::cout << (int)C::ugly(otherWork, (void*)11);
std::cout << (int)B::ugly(otherWork, (void*)19);
std::cout << std::endl;
return 0;
}
到那时,我认为我们可能已经超过了简单的malloc 的成本,所以你可能想使用它。