多態的なローカル変数を作成することはできません
B
のサブクラスはA
よりも多くの属性を持つ可能性があり、より多くの場所を占める可能性があるため、多態的なローカル変数を作成することはできませんA
。そのため、コンパイラは の最大のサブクラスのために十分なスペースを予約する必要がありA
ます。
- 数十のサブクラスがあり、そのうちの 1 つに多数の属性がある場合、これは多くのスペースを浪費します。
- パラメーターとして受け取ったサブクラスのインスタンスをローカル変数に
A
入れ、コードを動的ライブラリーに入れる場合、それにリンクするコードは、ライブラリー内のものよりも大きなサブクラスを宣言する可能性があるため、コンパイラーはとにかく、スタックに十分なスペースを割り当てていないでしょう。
そのため、自分でスペースを割り当てます
配置 newを使用すると、他の方法で割り当てたスペースでオブジェクトを初期化できます。
A
ただし、これらの手法は多くの余分なスペースを使用する可能性があり、説明した型よりも大きい、コンパイル時に不明なサブクラスへの参照 (ポインター) が与えられた場合は機能しません。
私が提案する解決策は、特定のサブクラスのスタック割り当てインスタンスへのポインターを使用して提供された関数を呼び出す、各サブクラスに一種のファクトリ メソッドを用意することです。提供された関数のシグネチャに追加の void* パラメータを追加したので、任意のデータを渡すことができます。
@MooingDuck は、以下のコメントで、テンプレートと C++11 を使用してこの実装を提案しました。C++11 の機能の恩恵を受けられないコード、またはクラスの代わりに構造体を使用する単純な C コードでこれが必要な場合 (struct B
最初のフィールドが type のstruct A
場合、「サブ構造体」のように操作できます) of 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
。