ルール
InterfaceクラスはPure virtual functionしか持てない
上記pure virtual functionは必ずpublicで宣言すること
C++にはInterfaceとして定義する構文は無い
そのためabstractクラスとpure virtual functionでinterfaceを実装する
使い方
- Base classからInterface Classを継承しておくことで、Baseクラスの子クラスからinterface classのfunctionを使うことができる
- Interface Classを継承しておけば新しいクラスを作ってもInterface classのfunctionを呼び出すことができる
まあなんでインターフェースがいるの?って疑問に関しては下記参照がいいかも。(Javaでの質問ですが。。)
"未来に備えて新しいクラスで共通的に使えるfunctionを定義しておくため"
みたいな感じでとりあえず消化しましたw
とりあえず例として、objをosに渡すようなoverload operatorがあります。
しかし、このoverload operatorは、それぞれのクラスを引数として指定しるため、下記のような場合だと、
Savingクラスを渡してもAccountクラス側のoverload operatorがcallされてしまいます。
#include <iostream> class Account { friend std::ostream &operator<<(std::ostream &os, const Account &acc); public: virtual void withdraw(double amount) { std::cout << "In Account Withdraw method is called" << std::endl; } virtual ~Account() {} }; std::ostream &operator<<(std::ostream &os, const Account &acc) { os << "Account display"; return os; } class Savings: public Account { friend std::ostream &operator<<(std::ostream &os, const Savings &sav); public: virtual void withdraw(double amount) { std::cout << "In Savings Withdraw method is called" << std::endl; } virtual ~Savings() {} }; std::ostream &operator<<(std::ostream &os, const Savings &sav) { os << "Savings display"; return os; } int main (){ Account a; Savings s; a.withdraw(1000); s.withdraw(1000); Account *aptr = new Account(); Account *sptr = new Savings(); std::cout << *aptr << std::endl; std::cout << *sptr << std::endl; //This is problematic delete aptr; delete sptr; }
実行結果
In Account Withdraw method is called In Savings Withdraw method is called Account display Account display
そこで、objを渡してprintするようなInterface classを作ってしまえば、各classで使えるようになるので、問題は解決するわけです。
気をつけないといけないのは、interface class内で作ったprint functionを各classの中でoverrideすること。かつ
関数宣言を完全にマッチさせること。
度々C++では、Interfaceクラスであることを明示的に示すために、I_***とするようです。
#include <iostream> class I_Printable { friend std::ostream &operator<<(std::ostream &os, const I_Printable &obj); public: virtual void print(std::ostream &os) const = 0; //pure virtual function }; std::ostream &operator<<(std::ostream &os, const I_Printable &obj){ obj.print(os); return os; } class Account: public I_Printable { public: virtual void withdraw(double amount) { std::cout << "In Account Withdraw method is called" << std::endl; } virtual void print(std::ostream &os) const override { os << "Account"; } virtual ~Account() {} }; class Savings: public Account { public: virtual void withdraw(double amount) { std::cout << "In Savings Withdraw method is called" << std::endl; } virtual void print(std::ostream &os) const override { os << "Savings"; } virtual ~Savings() {} }; class client1: public I_Printable { virtual void print(std::ostream &os) const override { os << "I'm client 1, nice to meet you."; } }; int main (){ Account a; Savings s; a.withdraw(1000); s.withdraw(1000); Account *aptr = new Account(); Account *sptr = new Savings(); std::cout << *aptr << std::endl; std::cout << *sptr << std::endl; client1 *cptr = new client1(); std::cout << *cptr << std::endl; delete aptr; delete sptr; delete cptr; }
実行結果
In Account Withdraw method is called In Savings Withdraw method is called Account Savings I'm client 1, nice to meet you.
処理の流れとしては、クラスオブジェクトのポインタがcoutで呼ばれたら、
Interfaceクラスの<<operatorメソッド内に遷移し、その後各クラス内のprint関数が呼ばれる。
また、強調したいのがclient1
というAccountクラスと何の関係の無いクラスを作ったとしても、
Interfaceクラスを継承することによって、print関数が使えていること。