C++のコンストラクタで「no matching function for call to」というエラーになる場合の対処
C++のコンストラクタで「no matching function for call to」というエラーになる場合の対処について紹介します。
1.問題点
C++で下記の簡単なサンプルを作りました。
foo.h
class Foo {
private:
int number;
public:
Foo(int num);
int print(void);
};
foo.cpp
#include "foo.h"
#include <iostream>
Foo::Foo(int num) {
number = num;
}
int Foo::print(void) {
std::cout << number << '\n';
}
test.cpp
#include "foo.h"
int main() {
Foo f(100);
f.print();
}
実行結果
% g++ foo.cpp test.cpp
% ./a.out
100
で、本題です。
上記のサンプルに、Fooクラスを継承するBarクラスを追加してみました。
bar.h
#include "foo.h"
class Bar: public Foo {
public:
Bar(int num);
int print(void);
};
bar.cpp
#include "bar.h"
#include <iostream>
Bar::Bar(int num) {
number = num;
}
int Bar::print(void) {
std::cout << number << '\n';
}
foo.hのメンバ変数numberは子クラスからもアクセスするのでprivateからprotectedに変更。
foo.h
class Foo {
protected:
int number;
public:
Foo(int num);
int print(void);
};
test.cppからのインクルードやmain()のクラス型はFooからBarにそれぞれ変更します。
test.cpp
#include "bar.h"
int main() {
Bar f(100);
f.print();
}
ビルドを実行すると、コンパイルで「no matching function for call to 'Foo::Foo()'」というエラーが発生します。
% g++ foo.cpp bar.cpp test.cpp
bar.cpp: コンストラクタ 'Bar::Bar(int)' 内:
bar.cpp:4:17: エラー: no matching function for call to 'Foo::Foo()'
Bar::Bar(int num) {
^
2.原因
コンパイルエラーの原因はつぎのいずれかになります。
- Fooクラスに引数が空のコンストラクタが定義されていない
- Barクラスのコンストラクタに継承するコンストラクタが定義されていない
ひとつめの原因の解説ですが、C++の子クラスでコンストラクタを起動すると、先に親のコンストラクタが呼ばれるようになっています。
前述のBarクラスのコンストラクタ定義では、Barのコンストラクタ起動前に、親クラスの引数なしのコンストラクタが起動されるのですが、Fooクラスには引数なしのコンストラクタが定義されていないため、「no matching function for call to 'Foo::Foo()'(Foo::Foo()の関数呼び出しが正常に行えない)」というエラーに遭遇してしまったようです。
あるいはBarクラスのコンストラクタを変更して、継承する親コンストラクタを定義すれば、親クラスに引数なしのコンストラクタを定義する必要はありません。
ということで、それぞれの原因に対する対処方法を下記に示します。
ちなみにC++にはJava言語の「super」に該当するものはありません。
3.対処方法1:Fooクラスに引数が空のコンストラクタを定義
ひとつめの対処方法は、赤字で示すように、Fooクラスに引数が空のコンストラクタを定義することです。
foo.h
class Foo {
protected:
int number;
public:
Foo();
Foo(int num);
int print(void);
};
foo.cpp
#include "foo.h"
#include <iostream>
Foo::Foo() {}
Foo::Foo(int num) {
number = num;
}
int Foo::print(void) {
std::cout << number << '\n';
}
実行結果
% g++ foo.cpp bar.cpp test.cpp
% ./a.out
100
4.対処方法2:Barクラスのコンストラクタに継承するコンストラクタを定義
もうひとつの対処方法は、Barクラスのコンストラクタ定義に、赤字で示すように継承するコンストラクタを定義することです。
bar.cpp
#include "bar.h"
#include <iostream>
Bar::Bar(int num): Foo(num) {
number = num;
}
int Bar::print(void) {
std::cout << number << '\n';
}
実行結果
% g++ foo.cpp bar.cpp test.cpp
% ./a.out
100
継承するコンストラクタのパラメータは変数名のみ記述すればOKです。型の記述は必要ありません。