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言語