你想做什么是行不通的。这是另一种方法,我基本上构建自己的类型基础设施:
#include <functional>
struct Base {
protected:
virtual ~Base() {}
Base() {}
public:
virtual size_t SizeRequired() const = 0;
virtual std::function<Base*(unsigned char* buffer)> Constructor() const = 0;
// note that standard delete is not standards compliant, because the memory
// was allocated as an array of unsigned char's
void SelfDelete() {
SelfDestroy();
delete[] reinterpret_cast<unsigned char*>(this);
}
// you can also create these things in other storage locations:
void SelfDestroy() {
this->~Base();
}
static void Delete( Base* b ) {
if (b)
b->SelfDelete();
}
std::function<Base*()> AllocateAndConstructor() const {
size_t required = this->SizeRequired();
auto constructor = this->Constructor();
return [required, constructor]()->Base* {
unsigned char* buff = new unsigned char[ required ];
return constructor( buff );
};
}
};
// CRTP class (google CRTP if you are confused what I'm doing)
template<typename Child>
struct BaseHelper: Base {
static Base* Construct(unsigned char* buffer) {
return new(buffer) Child();
}
static Base* Create() {
unsigned char* buff = new unsigned char[ sizeof(Child) ];
return Construct( buff );
};
virtual size_t SizeRequired() const {
return sizeof(Child);
}
virtual std::function<Base*(unsigned char* buffer)> Constructor() const {
return &BaseHelper<Child>::Construct;
}
};
// use:
struct Bar: BaseHelper<Bar> {
};
struct Foo: BaseHelper<Foo> {
};
Base* test(Base* b) {
auto creator = b->AllocateAndConstructor();
return creator();
}
#include <iostream>
int main() {
Base* b = Bar::Create(); // creates a Bar
Base* b2 = test(b); // creates another Bar, because b is a Bar
Base* f = Foo::Create(); // creates a Foo
Base* f2 = test(f); // creates another Foo, because f is a Foo
std::cout << (typeid(*b) == typeid(*b2)) << " == 1\n";
std::cout << (typeid(*f) == typeid(*f2)) << " == 1\n";
std::cout << (typeid(*f) == typeid(*b)) << " == 0\n";
Base::Delete(b);
Base::Delete(b2);
Base::Delete(f);
Base::Delete(f2);
Base::Delete(0); // does not crash
};
这意味着 Base 的每个运行时实例都带有构造 Base 实例的能力。覆盖 new 和 delete 可能比使用上述替换创建和删除操作更好,并且会让某人在堆栈上创建这些东西。
除非您知道自己在做什么,否则我建议您不要使用这种技术。
然而,有一些相对常见的模式,如克隆和工厂,它们与上述模式接近,但不那么愚蠢。