私には2つの「インターフェース」クラスがあります:AbstractAccess
とAbstractPrint
、およびAbstractRun
それらから継承し、それらのメソッドを使用するクラス。また、インターフェイスの実装は2つあります。AccessorforAbstractAccess
とPrintforです。AbstractPrint
#include <iostream>
using namespace std;
class AbstractAccess {
public:
virtual string access (void) = 0;
};
class AbstractPrint {
public:
virtual void print (string) = 0;
};
class AbstractRun : virtual public AbstractAccess, virtual public AbstractPrint {
public:
void run (void) {
print(access());
}
};
class Accessor : virtual public AbstractAccess {
public:
string access (void){
return name;
}
void setName(string name) {
this->name = name;
}
private:
string name;
};
class Print: public virtual AbstractPrint {
public:
void print (string s) {
cout << s << endl;
}
};
インターフェイスをAbstractRun
実装にキャストしたり、AbstractRunの「run」メソッドのみを使用して実装されたインターフェイスを使用する実装クラスRunを作成したりする方法はありますか?
あなたはすでに問題を解決しましたが、私はこれをさらに調査し、継承についての混乱を正したいと思います。
継承は、クラスが別のクラスと「isa」の関係にある場合に使用されます。派生クラスは、継承元のクラスの代わりになるはずです。
あなたの場合、あなたは安全にclass Print
aでclass AbstractPrint
あり、class Access
同様にaclass AbstractPrint
であると言うことができるので、ここでは継承は問題ありません。
一方、class AbstractRun
はではなく、でもAbstractPrint
ありませんAbstractAccess
。AbstractRun
単にハンドル/兼ね備えAbstractPrint
とAbstractAccess
。この関係は、aとaへの参照/ポインターをAbstractRun
持つという点で、集約(または構成)で抽象化する必要がAbstractRun
ありAbstractPrint
ます。これはAbstractRun
具体的になるので、名前をに変更しましょうRunner
。
class Runner
{
public:
// We now need a constructor to set the references.
Runner(AbstractAccess& access, AbstractPrint& print) :
accessor(access), printer(print) {}
void run (void) {
printer.print(accessor.access());
}
private:
AbstractAccess& accessor; // has a AbstractAccess
AbstractPrint& printer; // has a AbstractPrint
};
今Access
、そしてPrint
以前のように定義することができます。
しかし、それらも改善しましょう:
class Print: public virtual AbstractPrint {
public:
void print (string s) {
cout << s << endl;
}
};
仮想継承は必要ありません。仮想継承は、ダイヤモンドの問題を解決するために使用されます。しかし、AbstractRunnerが具体的なクラスにされた以上にダイヤモンドはありません。それでは、不要な修飾子を削除しましょう。
class Accessor : public AbstractAccess {
public:
string access (void){
return name;
}
void setName(string name) {
this->name = name;
}
private:
string name;
};
class Print: public AbstractPrint {
public:
void print (string s) {
cout << s << endl;
}
};
さらに、C ++ 11互換のコンパイラをoverride
使用している場合は、基本関数をオーバーライドするメソッドの修飾子を追加して、基本クラスから取得されたメソッドとそうでないメソッドを区別できるようにすることをお勧めします。
class Accessor : public AbstractAccess {
public:
string access (void) override { //overrides AbstractAcces method
return name;
}
void setName(string name) { //does not override. is a method at Accessor level
this->name = name;
}
private:
string name;
};
ここで、を初期化するときにRunner
、具象アクセサーとプリンターを渡す必要があります。これは次のように実行できます。
// Somewhere in a .cpp - file
Accessor accessor;
Print printer;
Runner runner(accessor, printe);
runner.run(); //will call printer and accessor through the references.
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加