2017-01-12 2 views
1

PCおよびPrinterは基底クラスItemの派生クラスです配列の要素をPCまたはPrinterまたはそれらの組み合わせにすることができるように、ユーザーの入力に基づいて配列のメモリを割り当てる必要があります。基本クラスのオブジェクトへのポインタの配列内の要素の型はどのように分かっていますか?

すべてのエラーが同じである:

ERROR: class "Item" has no member "getPC_Counter()" and "getP_Counter()" and "setCapacity()" and "setType()"

非常に奇妙な、複雑な方法で、私の質問をして申し訳ありませんが、私は本当に、適切に任意の方法を私の質問を説明する方法がわからないここに私のコードは次のと私は私がコメントで把握することはできませんか説明してみましょう:

#include<iostream> 
#include<string> 
using namespace std; 

class Item { 
    int ID; 
public: 
    Item() { 
     ID = 0; 
    } 
    Item(int i) { 
     ID = i; 
    } 
    void print() { 
     cout << ID << endl; 
    } 
    int getID() { 
     return ID; 
    } 
}; 

class PC :public Item { 
    static int PCc; 
    string type; 
public: 
    PC() { 
     type = ""; 
     PCc++; 
    } 
    void setType(string t) { 
     type = t; 
    } 
    void print() { 
     Item::print(); 
     cout << type << endl; 
    } 
    string getType() { 
     return type; 
    } 
    int getPC_Counter() { 
     return PCc; 
    } 
}; 

class Printer: public Item { 
    int capacity; 
    static int printerc; 
public: 
    Printer() { 
     capacity = 0; 
     printerc++; 
    } 
    void setCapacity(int c) { 
     capacity = c; 
    } 
    void print() { 
     Item::print(); 
     cout << capacity << endl; 
    } 
    int getCapacity() { 
     return capacity; 
    } 
    int getP_Counter() { 
     return printerc; 
    } 
}; 

int PC::PCc = 0; 
int Printer::printerc = 0; 

int main() { 
    Item *store[5]; 
    string c, t; 
    int cap; 

    cout << "pc or printer?" << endl; 
    for (int i = 0; i < 5; i++) { 
     cin >> c; 
     if (c == "pc") { 
      store[i] = new PC(); 
      cout << "type?" << endl; 
      cin >> t; 
      //here how do i use the current element as an object of type PC? 
      store[i]->setType(t); 
     } 
     if (c == "printer") { 
      store[i] = new Printer(); 
      cout << "capacity?" << endl; 
      cin >> cap; 
      //here how do i use the current element as an object of type Printer? 
      store[i]->setCapacity(cap); 
     } 
    } 
    //here how do i know if the element is of type printer or pc ? 
    //how do i use the getP_counter() and getPC_Counter funcions properly? 
    cout << "number of printers: " << store[0]->getP_Counter() << endl; 
    cout << "number of PCs: " << store[0]->getPC_Counter() << endl; 
    return 0; 
} 
+0

(またはnullptr C++ 11以上であれば)を使用します。これが機能するには、基本クラスに単一の仮想関数が必要です。デストラクタは通常の選択であり、基本クラスポインタを使用してオブジェクトを削除するので、ここでは適切です。あなたは現時点ではありませんが、メモリリークを避けたい場合にはそうなります。 –

+0

基本クラス 'Item'に仮想デストラクタがありません。それがなければ、 'store'配列内のそれらのアイテムを'削除 'すると、未定義の動作が呼び出されます。 – PaulMcKenzie

答えて

0

私はこれを行うには正しい方法はgetP_CountergetPC_Counter静的メンバ関数を作ることであると言うでしょう。とにかくこれらの関数は静的データにのみアクセスするため、動的ディスパッチの必要はありません。単に最初に実数型に割り当てることで、タイプを消去遅らせ、これらの機能を呼び出した後、アレイにこれを追加しsetCapacitysetTypeに対処するための

... 
    // make functions static 
    static int getPC_Counter() { 
     return PCc; 
    } 
... 

//later call static functions 
cout << "number of printers: " << Printer::getP_Counter() << '\n'; 
cout << "number of PCs: " << PC::getPC_Counter() << '\n'; 

PC* pc = new PC(); 
cout << "type?" << '\n'; 
cin >> t; 
//here how do i use the current element as an object of type PC? 
pc->setType(t); 
store[i] = pc; 
+0

ありがとう! – narlingz

+0

'Item'ポインタから' getCapacity'と 'getType'を呼び出す方法にはまだ問題があります。これはメンバ関数が必要なので、もう少し難しいです。私はあなたが同じ配列にPCとプリンタを置くつもりならば、少なくとも一貫したインターフェースを共有すべきだと言いたい。ダグラス・モエンスがこれについて答えてくれると思いますので、私は繰り返しはしません。 –

0

あなたがダウンし、必要な派生ポインタにあなたのベースポインタをキャストするdynamic_castを使用する必要があります。例えば、PCの場合:これはItem*(派生)PC*まで(塩基)キャストとして

dynamic_cast<PC*>(store[i])->setType(t); 

、動作します。

これはC++であるため、実際には生ポインタとCスタイルの配列の代わりにそれぞれstd::unique_ptrstd::vectorを使用してください。前者は動的キャスティングと多型を許可します。言い換えれば、使用時には:

std::vector<std::unique_ptr<Item>> store; 

代わりの

Item* store[5]; 
+0

ご協力いただきありがとうございます! – narlingz

0

この問題を解決する一般的なパターンは、ダブルディスパッチと呼ばれています。
最小限の作業例を次に示します。

struct Visitor; 

struct Base { 
    virtual void accept(Visitor &) = 0; 
}; 

struct Derived1: Base { 
    void accept(Visitor &v) override; 
    void f() {} 
}; 

struct Derived2: Base { 
    void accept(Visitor &v) override; 
    void g() {} 
}; 

struct Visitor { 
    void visit(Derived1 d) { d.f(); } 
    void visit(Derived2 d) { d.g(); } 
}; 

void Derived1::accept(Visitor &v) { v.visit(*this); } 
void Derived2::accept(Visitor &v) { v.visit(*this); } 

void func(Base &b) { 
    Visitor v; 
    b.accept(v); 
} 

int main() { 
    Derived1 d1; 
    Derived2 d2; 

    func(d1); 
    func(d2); 
} 

基本的な考え方は、あなたががあなたの階層に属しているクラスのすべてによってを受け入れているビジタークラスを使用することができるということです。
階層内のクラスがビジターを受け入れると、それは正しいタイプに昇格し、ビジターへの参照を渡します。

多形性に基づいており、解決策としてかなり侵略的ですが、dynamic_castやその他の手法を使用する必要はありません。

+0

ありがとう、私はそれを感謝します! – narlingz

0

質問は明確ではありません。おそらくそれは次のようなものです。

"ERROR: class "Item" has no member "getPC_Counter()" and "getP_Counter()" and "setCapacity()" and "setType()"

これらのエラーは自明です。基本型 "Item"に対してこれらの4つのメソッドをコーディングしていないだけです。


あなたがすなわち仮想メソッドを使用して、多型派生したオブジェクトに向かっている場合は、(基底クラスの)仮想メソッドは、派生のタイプを気にしてはいけません。基本クラスは派生クラスのインタフェース定義になります。

つまり、仮想メソッドprint()を呼び出すと、派生タイプのprint()が呼び出されます。


プリンタは、2(またはそれ以上)が存在するPCにはない方法(またはその逆)がある場合は、ベース・クラス(項目)と派生クラスとの間のこの「ミスマッチ」を解決するために近づきます。

すべての派生メソッドに基本クラスメソッドを使用することをお勧めします。だから、私はまた、処理するために、基本クラスのメソッドのために好む

Item::getPC_Counter() 
Item::getP_Counter() 
Item::setCapacity() 
Item::setType() 

基底クラス(すべての仮想としてマーク)(おそらくエラー/警告メッセージ)を実行するために派生尋ねるの概念に4つのメソッドを追加しますメソッドでサポートされていません。このサポートの欠如は、多元的な努力の中で「リンゴをオレンジと混合する」ことによって引き起こされます。 (私はかなり頻繁にこれを見てきました。)

をsetCapacity場合は()、派生クラスFooのために無意味である

// virtual 
Item::setCapacity(std::string lbl) 
{ std::cerr << " invalid setCapacity() for " << lbl << std::endl; } 

Foo::setCapacity() { Item::setCapacity("Foo"); } 

Fooの中の仮想メソッドが情報を送っ方法を参照してください。ベースクラスのメソッドに?

し、設定する能力を持っている派生クラスのバー、のために:

Bar::setCapacity() { /* perform Bar requirements */ } 

おそらく、より良いアプローチは、コンピュータのクラスで教えられているよりも多くの英語力が必要です。この方法では、それぞれの派生クラスがサポートできる動詞を作成する必要があります。

古典的な例はおそらくクラスの動物であり、派生した種です。すべての種が樹皮をつくことはできませんが、考えたいと思っているものはすべて声を出したり、あるいは話したり、食べたりすることができます。

Animal :: vocalize()は、dog :: vocalize(){bark();によってサポートされています。 }、 cat :: vocalize(){meow(); }ここで、樹皮とニオは種(または派生クラス)固有のメソッドです。

printer :: setCapacity()、またはpc :: setCapacity()の意味を推測できません。それを定義する必要があります。そして、PCとプリンタの両方がサポートする、より一般的な動詞を思いつきましょう。そして、おそらくこれらの事務機器オブジェクトは、これらの問題に対処すべきではありません。

多型チュートリアルを確認してください。オブジェクトを慎重に計画します。

あなたの改善のために質問を更新してください。

+0

あなたの優れた説明に感謝します – narlingz

0

あなたは、統計的または動的に、彼は 例でどのような種類を知るためにそのポインタをキャストすることができます

`auto e = dynamic_pointer_cast<Type>(pointer);` 

動的キャストされている高価なものとあなたはおそらくそれが

どのタイプであるuが知っていればstatic_castを使用したいです
auto e = static_pointer_cast<expecting type>(pointer); 

例:

auto e = static_pointer_cast<Pc>(pointer); 

らuは生のポインタを使用している場合ので、あなたはstatic_castを代わりにstatic_pointer_cast唯一の方法は、それはNULLを返さないまで `dynamic_cast`を使用し、それぞれのタイプを試してみることです

関連する問題