工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> C言語

C++仮想関数マスター:概念、実例、overrideキーワード

C++仮想関数

このチュートリアルでは、C++仮想関数の目的と実践的な使い方をコード例で解説します。

仮想関数は、派生クラスでオーバーライドされることを期待する基底クラスのメンバ関数です。関数をvirtualで宣言すると、基底クラスポインタや参照経由でアクセスしても、最も派生した実装が呼び出されます。

基底クラスに非仮想メンバがある場合、基底ポインタ経由で呼び出すと、実際のオブジェクト型に関わらず常に基底版が実行されます。以下を考えてみてください:

class Base {
public:
    void print() { // 基底実装 }
};

class Derived : public Base {
public:
    void print() { // 派生実装 }
};

以下のプログラムでは、Base*がDerivedインスタンスを指していますが、print()は基底版に解決されます:

int main() {
    Derived derived1;
    Base* base1 = &derived1;
    base1->print(); // Base::print()を呼び出し
    return 0;
}

ポリモーフィックな振る舞いを実現するには、基底クラスで関数をvirtualで宣言します:

class Base {
public:
    virtual void print() { // 基底実装 }
};

仮想関数はC++ポリモーフィズムの中核です。詳細についてはC++ポリモーフィズムガイドを参照してください。


例1: 基本的な仮想関数の使用

#include <iostream>
using namespace std;

class Base {
public:
    virtual void print() {
        cout << "Base Function" << endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        cout << "Derived Function" << endl;
    }
};

int main() {
    Derived derived1;
    Base* base1 = &derived1;
    base1->print(); // Derived Functionを出力
    return 0;
}

出力

Derived Function

Base::printがvirtualであるため、基底ポインタ経由の呼び出しでもDerived::printにディスパッチされます。

C++仮想関数マスター:概念、実例、overrideキーワード

C++ override識別子

C++11以降、overrideキーワードは、関数が本当に仮想基底メンバをオーバーライドしていることをコンパイラに検証させることで、誤ったオーバーライドを防ぎます。

例:

class Base {
public:
    virtual void print() { /* 基底実装 */ }
};

class Derived : public Base {
public:
    void print() override { /* 派生実装 */ }
};

クラス外部でオーバーライド関数を定義する場合:

class Derived : public Base {
public:
    void print() override; // 宣言
};

void Derived::print() { // 実装
}

overrideの安全な使用

overrideなしでは、タイポやシグネチャの不一致がサイレントに新しい関数を生成し、オーバーライドにならないため、微妙なバグを招きます。overrideを付けるとコンパイラが即座にエラーを出します。よくある落とし穴:


仮想関数の実践的活用

Animal基底クラスと派生Dog、Catクラスを考えます。各クラスはコンストラクタで初期化されるtypeメンバを持ちます。

class Animal {
private:
    string type;
public:
    Animal() : type("Animal") {}
    virtual string getType() const { return type; }
};

class Dog : public Animal {
private:
    string type;
public:
    Dog() : type("Dog") {}
    string getType() const override { return type; }
};

class Cat : public Animal {
private:
    string type;
public:
    Cat() : type("Cat") {}
    string getType() const override { return type; }
};

getType()をvirtualにすると、単一のヘルパーで任意の動物を出力できます:

void print(Animal* ani) {
    cout << "Animal: " << ani->getType() << endl;
}

main()での使用:

int main() {
    Animal* animal1 = new Animal();
    Animal* dog1 = new Dog();
    Animal* cat1 = new Cat();
    print(animal1);
    print(dog1);
    print(cat1);
    delete animal1;
    delete dog1;
    delete cat1;
    return 0;
}

出力

Animal: Animal
Animal: Dog
Animal: Cat

getType()をvirtualにすることで、各派生クラスにprint()ロジックを複製せず、正しいtypeがアクセスされることを保証できます。

C言語

  1. C++配列を関数に渡す完全ガイド:1次元・多次元配列の実例付き
  2. C++クラスとオブジェクト完全ガイド:オブジェクト指向プログラミングの実践
  3. C++フレンド関数とフレンドクラス:アクセス制御のマスター
  4. C++クラステンプレート完全ガイド:実践的なジェネリックプログラミング
  5. C++関数を実例で徹底解説:基本から応用まで
  6. C言語の関数マスター:構造、宣言、ベストプラクティス
  7. C++ストレージクラス完全解説:スコープ、ライフタイム、使い方
  8. C++オーバーロード完全マスター:関数と演算子のオーバーロード
  9. C++ポリモーフィズム完全理解:仮想関数と純粋仮想関数
  10. C++データ抽象化完全マスター:インターフェースと実装の分離
  11. Verilog関数のマスター:効率的なRTL設計のために