(1) ある種、しかし、あなたがやろうとしている方法とはまったく異なります。基本的に、特殊化で関数を定義する必要があります。基本クラスと派生クラスを宣言するときとはかなり異なります。
template <typename T> class Shape {
static_assert(false, "Not implemented");
};
template <> class Shape<bool> {
void Foo(bool a, std::string b) {...}
};
template <> class Shape<int> {
void Foo(int, std::string, whatever else) {...}
};
特殊化されていない元の Shape で Foo を定義したとしても、特殊化には影響しません。完全な専門化は元のテンプレートを拡張するのではなく、元のテンプレートを置き換えます!
(2) static_assert を使用します。上記の例を参照してください。
(3) はい、テンプレートと継承を混在させることができます。仮想関数のランタイム ポリモーフィズムと静的ポリモーフィズム。テンプレート パラメーターはコンパイル時に認識されている必要がありますが、ランタイム ポリモーフィック オブジェクトの正確な型は認識されていません。これらは基本クラスの参照によって参照される可能性があるためです。上記のテンプレート化された例では、単純に言うことはできません
template <class T> Shape {...};
...
Shape* myShape; // Compiler error: Shape requires a template parameter
ただし、継承を使用すると、次のことができます。
class ShapeBase { virtual void Foo() = 0; };
class Circle : public ShapeBase { virtual void Foo() { ... } };
class Square : public ShapeBase { virtual void Foo() { ... } };
...
Shape* myShape = new Circle;
myShape->Foo(); // calls Circle->Foo()
継承を使用する場合は、関数のシグネチャが一致する必要があることに注意してください。これは、実行時まで決定を延期するために支払う代償です。