C++で学ぶ!別クラス関数の呼び出し方法7選

C++のクラス間関数呼び出しを学ぶイメージC++
この記事は約13分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

この記事を読めば、C++における別クラスの関数を呼び出す方法が理解できます。

プログラミング初心者から上級者まで、C++の基本的なクラスと関数の概念から始めて、具体的な使い方までを分かりやすく解説します。

●別クラスの関数を呼び出す方法

C++では、プログラムをモジュール化し、機能を効率的に管理するために、クラスを使用します。

異なるクラスに属する関数を呼び出すことは、C++のオブジェクト指向プログラミングの基本的な概念です。

ここでは、具体的なサンプルコードを通じて、別クラスの関数を呼び出す方法を学びます。

○サンプルコード1:基本的な関数呼び出し

最も単純な形の別クラスの関数の呼び出しは、クラスのインスタンスを作成し、そのインスタンスを通じて関数を呼び出すことです。

例えば、下記のコードでは、ClassAのメソッドfunctionAを呼び出しています。

#include <iostream>

class ClassA {
public:
    void functionA() {
        std::cout << "ClassAのfunctionAが呼び出されました。" << std::endl;
    }
};

int main() {
    ClassA objA;
    objA.functionA();
    return 0;
}

このコードでは、まずClassAクラスにfunctionAという公開メソッドを定義しています。

main関数内でClassAのオブジェクトobjAを作成し、objA.functionA()を呼び出すことで、ClassAfunctionAメソッドを実行しています。

○サンプルコード2:引数と戻り値を持つ関数の呼び出し

別クラスの関数が引数や戻り値を持っている場合、それらを使用して関数を呼び出すことができます。

下記の例では、ClassBfunctionBメソッドが整数の引数を取り、整数を返すように定義されています。

#include <iostream>

class ClassB {
public:
    int functionB(int num) {
        return num * 2;
    }
};

int main() {
    ClassB objB;
    int result = objB.functionB(5);
    std::cout << "結果: " << result << std::endl;
    return 0;
}

このコードのfunctionBは引数numを受け取り、num * 2の計算結果を返します。

main関数ではClassBのインスタンスを作成し、functionBを引数5で呼び出しています。

戻り値はresultに格納され、それを表示しています。

○サンプルコード3:オーバーロードされた関数の呼び出し

関数のオーバーロードは、同じ名前の関数を異なる引数で複数定義することです。

C++ではこの特性を利用して、異なるタイプや数の引数を持つ同名の関数を作成できます。

ここでは、オーバーロードされた関数の例を紹介します。

#include <iostream>

class ClassC {
public:
    void functionC() {
        std::cout << "引数なしのfunctionCが呼び出されました。" << std::endl;
    }
    void functionC(int num) {
        std::cout << "引数 " << num << " のfunctionCが呼び出されました。" << std::endl;
    }
};

int main() {
    ClassC objC;
    objC.functionC();
    objC.functionC(10);
    return 0;
}

このコードでは、ClassCfunctionCを二つ定義しています。

一つ目は引数なし、二つ目は整数型の引数を取ります。

main関数内で、objCを通じて両方のfunctionCメソッドを呼び出しています。

オーバーロードされた関数は引数の型や数に応じて適切な関数が自動的に選択されます。

○サンプルコード4:友達関数を用いた呼び出し

友達関数(friend function)は、クラスのプライベートメンバにアクセスできる特別な関数です。

この関数は、クラスの外部で定義されますが、クラスの内部で友達として宣言されます。

#include <iostream>

class ClassD {
private:
    int value;

public:
    ClassD(int val) : value(val) {}

    friend void showValue(ClassD& obj);
};

void showValue(ClassD& obj) {
    std::cout << "ClassDのvalue: " << obj.value << std::endl;
}

int main() {
    ClassD objD(15);
    showValue(objD);
    return 0;
}

この例では、ClassDのプライベートメンバvalueshowValue関数がアクセスしています。

main関数ではClassDのオブジェクトを作成し、そのオブジェクトに対してshowValue関数を呼び出しています。

友達関数はクラスのカプセル化を維持しながら、外部関数がクラスの内部メンバにアクセスする手段を提供します。

●よくあるエラーと対処法

C++プログラミングでは、特にクラス間での関数呼び出しにおいて、さまざまなエラーが発生することがあります。

これらのエラーを理解し、適切に対処することは、効率的なプログラミングにとって重要です。

ここでは、よく遭遇するエラーとその対処方法について解説します。

○エラー例1:関数の未定義エラー

関数の未定義エラーは、クラスのメソッドが呼び出されたにもかかわらず、その定義が見つからない場合に発生します。

このエラーを解決するには、関数が適切に宣言されているか、そして宣言と一致する定義がプログラム内に存在するかを確認する必要があります。

// エラーの例
class MyClass {
public:
    void myFunction();
};

// myFunctionの定義が存在しないため、エラーが発生する

この例では、MyClassクラス内にmyFunctionが宣言されていますが、定義が存在しないためエラーが発生します。

この問題を解決するためには、myFunctionの適切な定義を追加する必要があります。

○エラー例2:アクセス制限エラー

アクセス制限エラーは、プライベートまたは保護されたメンバに不適切にアクセスしようとした場合に発生します。

このエラーを避けるためには、メンバのアクセスレベル(public、private、protected)に注意し、適切なアクセス方法を使用する必要があります。

class MyClass {
private:
    void privateFunction() {}
};

int main() {
    MyClass obj;
    // 以下の行でアクセス制限エラーが発生する
    obj.privateFunction();
}

この例では、privateFunctionがプライベートメソッドとして定義されており、クラス外からのアクセスは許可されていません。

したがって、main関数から直接呼び出そうとするとアクセス制限エラーが発生します。

○エラー例3:型不一致のエラー

型不一致のエラーは、関数に渡される引数の型が関数の定義と一致しない場合に発生します。

このエラーを解決するには、関数呼び出しで使用される引数の型が関数のパラメータの型と一致しているか確認する必要があります。

class MyClass {
public:
    void function(int num) {}
};

int main() {
    MyClass obj;
    // 以下の行で型不一致のエラーが発生する
    obj.function("文字列");
}

この例では、functionメソッドが整数型の引数を期待しているにも関わらず、文字列を引数として渡しているため、型不一致のエラーが発生します。

正しい型の引数を提供することで、この問題を解決できます。

●別クラス関数の応用例

C++でのクラス間の関数呼び出しは、基本的な使用方法だけでなく、さまざまな応用が可能です。

継承、テンプレート、ラムダ式などを利用することで、より柔軟かつ強力なプログラムを作成することができます。

ここでは、これらの応用例を具体的なサンプルコードと共に解説します。

○サンプルコード5:継承を使った関数の呼び出し

継承は、あるクラス(基底クラス)のプロパティやメソッドを別のクラス(派生クラス)が継承することを可能にします。

これにより、コードの再利用性が高まります。

#include <iostream>

class BaseClass {
public:
    void baseFunction() {
        std::cout << "基底クラスの関数が呼び出されました。" << std::endl;
    }
};

class DerivedClass : public BaseClass {};

int main() {
    DerivedClass obj;
    obj.baseFunction();  // 基底クラスの関数を呼び出す
    return 0;
}

このコードでは、BaseClassbaseFunctionメソッドがDerivedClassによって継承されています。

DerivedClassのインスタンスを作成し、baseFunctionを呼び出しています。

○サンプルコード6:テンプレート関数の呼び出し

テンプレートは、データ型に依存しない汎用的な関数やクラスを作成するための機能です。

テンプレートを使用すると、さまざまな型で同じ操作を行う関数やクラスを簡単に作成できます。

#include <iostream>

template<typename T>
class MyClass {
public:
    void function(T value) {
        std::cout << "値: " << value << std::endl;
    }
};

int main() {
    MyClass<int> objInt;
    MyClass<std::string> objString;

    objInt.function(10);         // 整数型で関数を呼び出す
    objString.function("テキスト");  // 文字列型で関数を呼び出す
    return 0;
}

この例では、MyClassはテンプレートクラスとして定義されており、functionメソッドは任意の型の引数を受け取ることができます。

○サンプルコード7:ラムダ式を用いた関数の呼び出し

ラムダ式は、無名関数を作成するための便利な手段です。

ラムダ式を使用すると、コードの場所に応じて小さな関数を直接記述することができます。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::for_each(numbers.begin(), numbers.end(), [](int n) {
        std::cout << n << " ";
    });
    return 0;
}

この例では、std::for_each関数にラムダ式を渡して、ベクトルの各要素を出力しています。

ラムダ式は[](int n) { ... }の部分で、ベクトルの各要素に対して実行される無名関数を定義しています。

●C++プログラミングの豆知識

C++のプログラミングは奥深く、効率的なコードを書くためには多くの知識が必要です。

ここでは、C++プログラミングの豆知識として、最適化されたコードの書き方とC++11以降に導入された新機能について解説します。

○豆知識1:最適化されたコードの書き方

C++で効率的なコードを書くためには、下記のような点に注意することが重要です。

  1. ループの最適化 -> 不必要な計算をループの外に移動させ、計算の回数を減らします
  2. データ構造の選択 -> プログラムの目的に合ったデータ構造を選択し、データへのアクセスや操作を効率化します
  3. インライン関数の使用 -> 小さな関数はインライン化することで関数呼び出しのオーバーヘッドを減らすことができます

例えば、下記のようなコードでは、ループ外で計算を行うことで効率を向上させています。

int main() {
    int total = 0;
    int addValue = 5;
    for (int i = 0; i < 100; ++i) {
        total += addValue; // addValueの計算をループ外で行う
    }
}

このように、計算をループの外に移動することで、ループの各イテレーションでの計算回数を減らし、パフォーマンスを向上させることができます。

○豆知識2:C++11以降の新機能

C++11では多くの新機能が導入されました

。これらの機能を利用することで、より読みやすく効率的なコードを書くことができます。

特筆すべき新機能には以下のようなものがあります。

  • 自動型推論(auto) -> 変数の型をコンパイラに自動で推論させることができます
  • 範囲ベースのforループ -> コレクションを簡単にループ処理することができます
  • ラムダ式 -> 無名関数を使ってコードをよりコンパクトに書くことができます

ここでは範囲ベースのforループの例を見ていきましょう。

#include <vector>
#include <iostream>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    for (auto num : numbers) {
        std::cout << num << std::endl;
    }
}

このコードでは、std::vectorの各要素に対してループ処理を行っています。

C++11の範囲ベースのforループを使用することで、よりシンプルで読みやすいコードを書くことができます。

まとめ

この記事では、C++における別クラスの関数を呼び出す方法を幅広く解説しました。

基本的な関数の呼び出しから、テンプレート関数やラムダ式を使った応用例まで、豊富なサンプルコードとともに、初心者から上級者まで理解できるように詳しく説明してきました。

C++11以降の新機能についても触れ、最適化されたコードの書き方を学ぶことができたかと思います。

これらの知識を活用し、C++プログラミングのスキルをさらに深めていきましょう。