あなたがやりたいことはうまくいきません。これは、基本的に独自のタイプのインフラストラクチャを構築する代替アプローチです。
#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をオーバーライドすると、上記の置換の作成および削除操作を使用するよりもうまく機能する可能性があり、誰かがスタック上にこれらのものを作成できるようになります。
自分が何をしているのかわからない限り、この種のテクニックには反対することをお勧めします。
ただし、クローン作成やファクトリなど、上記に近いが少しばかげていない比較的一般的なパターンがあります。