C++ 仮想関数
C++ 仮想関数
このチュートリアルでは、例を使用して C++ 仮想関数とその使用法について学習します。
仮想関数は、派生クラスで再定義することが期待される基本クラスのメンバー関数です。
基本的に、関数が確実にオーバーライドされるようにするために、基本クラスで仮想関数が使用されます。 .これは、基本クラスのポインターが派生クラスのオブジェクトを指す場合に特に当てはまります。
たとえば、以下のコードを考えてみましょう:
class Base {
public:
void print() {
// code
}
};
class Derived : public Base {
public:
void print() {
// code
}
};
後で、Base
のポインターを作成すると、 Derived
のオブジェクトを指す型 クラスを作成して print()
を呼び出します 関数、それは print()
を呼び出します Base
の機能 クラス。
つまり、Base
のメンバー関数 はオーバーライドされません。
int main() {
Derived derived1;
Base* base1 = &derived1;
// calls function of Base class
base1->print();
return 0;
}
これを避けるために、print()
を宣言します。 Base
の機能 virtual
を使用してクラスを仮想として キーワード。
class Base {
public:
virtual void print() {
// code
}
};
仮想関数は、C++ におけるポリモーフィズムの不可欠な部分です。詳細については、C++ ポリモーフィズムに関するチュートリアルをご覧ください。
例 1:C++ 仮想関数
#include <iostream>
using namespace std;
class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};
class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};
int main() {
Derived derived1;
// pointer of Base type that points to derived1
Base* base1 = &derived1;
// calls member function of Derived class
base1->print();
return 0;
}
出力
Derived Function
ここでは、print()
を宣言しています。 Base
の関数 virtual
として .
したがって、Base
のポインターを使用する場合でも、この関数はオーバーライドされます。 Derived
を指す型 オブジェクト派生1 .

C++ オーバーライド識別子
C++ 11 では、新しい識別子 override
が提供されました これは、仮想関数の使用中にバグを回避するのに非常に役立ちます。
この識別子は、基本クラスのメンバー関数をオーバーライドする派生クラスのメンバー関数を指定します。
たとえば、
class Base {
public:
virtual void print() {
// code
}
};
class Derived : public Base {
public:
void print() override {
// code
}
};
Derived
で関数プロトタイプを使用する場合 クラスを作成し、その関数をクラス外で定義する場合は、次のコードを使用します:
class Derived : public Base {
public:
// function prototype
void print() override;
};
// function definition
void Derived::print() {
// code
}
C++ オーバーライドの使用
仮想関数を使用する場合、派生クラスのメンバー関数を宣言する際に間違いを犯す可能性があります。
override
の使用 identifier は、これらの誤りが発生した場合にコンパイラにエラー メッセージを表示するように促します。
それ以外の場合、プログラムは単純にコンパイルされますが、仮想関数はオーバーライドされません。
考えられる間違いの例:
- 名前が正しくない関数: たとえば、基本クラスの仮想関数の名前が
print()
の場合 ですが、派生クラスのオーバーライド関数に誤ってpint()
という名前を付けています . - 戻り値の型が異なる関数: たとえば、仮想関数が
void
の場合 タイプですが、派生クラスの関数はint
です 入力してください。 - 異なるパラメータを持つ関数: 仮想関数と派生クラスの関数のパラメーターが一致しない場合。
- 基本クラスで仮想関数が宣言されていません。
C++ 仮想関数の使用
基本クラス Animal
があるとします および派生クラス Dog
と Cat
.
各クラスに type という名前のデータ メンバーがあるとします。 .これらの変数がそれぞれのコンストラクターによって初期化されるとします。
class Animal {
private:
string type;
... .. ...
public:
Animal(): type("Animal") {}
... .. ...
};
class Dog : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Dog") {}
... .. ...
};
class Cat : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Cat") {}
... .. ...
};
ここで、プログラムで 2 つの public
を作成する必要があるとします。 各クラスの関数:
getType()
type の値を返す print()
type の値を出力します これらの両方の関数を各クラスで別々に作成してオーバーライドすることもできますが、これは長くて面倒です。
または getType()
にすることもできます バーチャル Animal
で クラスを作成してから、単一の個別の print()
を作成します Animal
のポインタを受け取る関数 type を引数として使用します。次に、この単一の関数を使用して仮想関数をオーバーライドできます。
class Animal {
... .. ...
public:
... .. ...
virtual string getType {...}
};
... .. ...
... .. ...
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
これにより、コードが短くなります。 、クリーナー 、繰り返しが少ない .
例 2:C++ 仮想関数のデモ
// C++ program to demonstrate the use of virtual function
#include <iostream>
#include <string>
using namespace std;
class Animal {
private:
string type;
public:
// constructor to initialize type
Animal() : type("Animal") {}
// declare virtual function
virtual string getType() {
return type;
}
};
class Dog : public Animal {
private:
string type;
public:
// constructor to initialize type
Dog() : type("Dog") {}
string getType() override {
return type;
}
};
class Cat : public Animal {
private:
string type;
public:
// constructor to initialize type
Cat() : type("Cat") {}
string getType() override {
return type;
}
};
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
int main() {
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
print(animal1);
print(dog1);
print(cat1);
return 0;
}
出力
Animal: Animal Animal: Dog Animal: Cat
ここでは、仮想関数 getType()
を使用しました。 そして Animal
ポインター ani print()
の繰り返しを避けるために すべてのクラスで機能します。
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
main()
で 、3 つの Animal
を作成しました Animal
のオブジェクトを動的に作成するポインタ 、 Dog
と Cat
クラス。
// dynamically create objects using Animal pointers
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
次に print()
を呼び出します これらのポインターを使用する関数:
print(animal1)
の場合 が呼び出されると、ポインタは Animal
を指します 物体。 Animal
の仮想関数 クラスは print()
内で実行されます .print(dog1)
の場合 が呼び出されると、ポインタは Dog
を指します 物体。したがって、仮想関数がオーバーライドされ、Dog
の関数が print()
内で実行されます .print(cat1)
の場合 が呼び出されると、ポインタは Cat
を指します 物体。したがって、仮想関数がオーバーライドされ、Cat
の関数が print()
内で実行されます .C言語