関数が仮想として定義されている場合、それは正確には何を意味し、純粋仮想と同じですか?
ベストアンサー1
からWikipedia の仮想関数...
オブジェクト指向プログラミングの C++ や Object Pascal などの言語では、仮想関数または仮想メソッドは、動的ディスパッチが容易に実行できる、継承およびオーバーライド可能な関数またはメソッドです。この概念は、オブジェクト指向プログラミング (OOP) の (実行時) ポリモーフィズム部分の重要な部分です。簡単に言うと、仮想関数は実行されるターゲット関数を定義しますが、ターゲットはコンパイル時にわからない場合があります。
非仮想関数とは異なり、仮想関数がオーバーライドされると、作成されたレベルだけでなく、クラス階層のすべてのレベルで、最も派生したバージョンが使用されます。したがって、基本クラスの 1 つのメソッドが仮想メソッドを呼び出す場合、基本クラスで定義されたバージョンではなく、派生クラスで定義されたバージョンが使用されます。
例えば、このコードを実行すると
struct Base
{
virtual ~Base() = default;
virtual void foo()
{
std::cout << "Base::Foo" << std::endl;
}
};
struct Derived final: Base
{
void foo() override
{
std::cout << "Derived::Foo" << std::endl;
}
};
int main()
{
Base base;
base.foo();
Derived derived;
derived.foo();
Base* derived_as_base = &derived;
derived_as_base->foo();
}
これが出力結果です
Base::Foo
Derived::Foo
Derived::Foo
これは、派生クラスでオーバーライドできる非仮想関数とは対照的ですが、「新しい」バージョンは派生クラス以下でのみ使用され、基本クラスの機能はまったく変更されません。
上記のコードを次のように変更すると、これがわかります。
struct Base
{
void foo()
{
std::cout << "Base::Foo" << std::endl;
}
};
struct Derived final: Base
{
void foo()
{
std::cout << "Derived::Foo" << std::endl;
}
};
次のような出力が生成される。
Base::Foo
Derived::Foo
Base::Foo
一方..
純粋仮想関数または純粋仮想メソッドは、派生クラスが抽象クラスでない場合、派生クラスによって実装される必要がある仮想関数です。
純粋仮想メソッドが存在する場合、クラスは「抽象」であり、独自にインスタンス化することはできません。代わりに、純粋仮想メソッドを実装する派生クラスを使用する必要があります。純粋仮想は基本クラスではまったく定義されていないため、派生クラスで定義する必要があります。そうしないと、その派生クラスも抽象クラスとなり、インスタンス化できません。抽象メソッドを持たないクラスのみをインスタンス化できます。
純粋な仮想セットアップは次のようになります
struct Base
{
virtual ~Base() = default;
virtual void foo() = 0;
};
struct Derived final: Base
{
void foo() override
{
std::cout << "Derived::Foo" << std::endl;
}
};
int main()
{
// error: cannot declare variable 'base' to be of abstract type 'Base'
// Base base;
// base.foo();
Derived derived;
derived.foo();
Base* derived_as_base = &derived;
derived_as_base->foo();
}
出力は、純粋であろうとなかろうと、仮想関数から期待されるものと一致する必要があります。
Derived::Foo
Derived::Foo
つまり、仮想は基本クラスの機能をオーバーライドする方法を提供し、純粋仮想はそれを必要とします。