前提知識が間違っている可能性があるので2点確認です。
・継承の種類について(現在のコードでprivate継承しているのは意図的なのか)
・virtual関数はオーバーライドするために必要
この前提が間違っていると回答ができません。
以下、すべてこちらの予想で回答するので
質問内容とずれた回答をするかもしれません。
ご了承ください。
【private継承が意図的だった場合の回答】
private継承したスーパークラスのメソッドを
継承先でpublicとして公開するにはオーバーライドが必須になります。
アクセス装飾子を変更するためにプロトタイプ宣言が必須になるので、
実装を書く必要があります。
コード:
#include <iostream>
class BASE {
public:
int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
// class SUB : private BASE と class SUB : BASE は同じ
class SUB : private BASE {
public:
SUB();
int g() override; // C++11対応でない場合はoverrideキーワードを削除してください
int h();
};
SUB::SUB() {
}
int SUB::g() {
// 実装は必須
return BASE::g();
}
int SUB::h() {
return 2;
}
int main() {
using namespace std;
cout << BASE().g() << endl;
cout << SUB().g() << endl;
rewind(stdin), getchar();
return 0;
}
【private継承が意図的でない場合の回答】
virtualキーワードは必要なく以下のコードで十分です。
コード:
class BASE {
public:
int f();
int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : public BASE {
public:
SUB();
int h();
};
SUB::SUB() {
}
int SUB::h() {
return 2;
}
int main() {
using namespace std;
SUB inst;
cout << inst.g() << endl; // BASE::g()が呼ばれている。
rewind(stdin), getchar();
return 0;
}
次に
virtual関数を使用した際のコードです。
まず、オーバーライドしない場合の例です。
コード:
#include <iostream>
class BASE {
public:
int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : public BASE {
public:
SUB();
// int g() override; // オーバーライドしないのであればプロトタイプ宣言しない
int h();
};
SUB::SUB() {
}
int SUB::h() {
return 2;
}
int main() {
using namespace std;
cout << BASE().g() << endl; // BASE::g()が呼ばれる
cout << SUB().g() << endl; // BASE::g()が呼ばれる
rewind(stdin), getchar();
return 0;
}
次に、オーバーライドする場合の例です。
コード:
#include <iostream>
class BASE {
public:
int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : public BASE {
public:
SUB();
int g() override; // C++11対応でない場合はoverrideキーワードを削除してください
int h();
};
SUB::SUB() {
}
int SUB::g() {
// オーバーライドは処理内容を変更するために定義する
// 3を返却するようにする。
return 3;
}
int SUB::h() {
return 2;
}
int main() {
using namespace std;
cout << BASE().g() << endl;
cout << SUB().g() << endl;
rewind(stdin), getchar();
return 0;
}
【その他】
コンパイルエラーに関して、
インスタンスを使って使用する際にどちらもエラーすると思います。
コード:
#include <iostream>
class BASE {
public:
virtual int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : BASE {
public:
int g(); // BASE::g()を公開するには実体が必要
int h();
};
int SUB::h() {
return 2;
}
int main() {
using namespace std;
cout << SUB().g() << endl; // 実体が無いのでエラー
return 0;
}
また、上記のコードに関連して
gasbombe さんが書きました:
サブクラスのほうでコンストラクタを作ると、
以下のコードでエラーが出ました。
コード:
class BASE {
public:
virtual int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : BASE {
public:
SUB();
int g();
int h();
};
SUB::SUB() {
}
int SUB::h() {
return 2;
}
int main() {
return 0;
}
のコードは、コンストラクタを定義したことが理由でエラーしたわけでなく
SUB::g()の実体がないためエラーをしています。
コード:
class BASE {
public:
virtual int f();
virtual int g();
};
int BASE::f() {
return 0;
}
int BASE::g() {
return 1;
}
class SUB : BASE {
public:
SUB();
int g();
int h();
};
SUB::SUB() {
}
int SUB::g() {
return 3;
}
int SUB::h() {
return 2;
}
int main() {
return 0;
}