簡體   English   中英

我怎么知道指向基類對象的指針數組中元素的類型,它將為派生類分配內存

[英]how do i know what is the type of an element in an array of pointers to an object of base class, that will allocate memory for derived classes

PCPrinter是基類Item派生類,如果我創建一個Item類型的指針數組,我想根據用戶的輸入為數組分配內存,這樣它就可以使數組中的元素成為PCPrinter s或它們的混合。

所有錯誤都是一樣的:

錯誤:類“Item”沒有成員“getPC_Counter()”和“getP_Counter()”和“setCapacity()”和“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;
}

您需要使用dynamic_cast將基指針向下轉換為所需的派生指針。 例如,在PC的情況下:

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

將工作,因為這將Item* (基礎)下放到PC* (派生的)。

注意,因為這是C ++,你應該分別使用std::unique_ptrstd::vector而不是原始指針和C風格的數組。 前者仍然允許動態轉換和多態。 換句話說,使用:

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

代替

Item* store[5];

我想說這樣做的正確方法是使getP_CountergetPC_Counter靜態成員函數。 然后不需要動態調度,因為這些函數無論如何只訪問靜態數據。

...
    // 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';

處理setCapacitysetType只是通過最初分配給真實類型來延遲擦除類型,並在調用這些函數后將其添加到數組中。

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;

解決該問題的常見模式稱為雙重調度。
它遵循一個最小的工作示例:

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或任何其他技術。

問題不明確。 也許它是:你為什么得到:

“錯誤:類”項“沒有成員”getPC_Counter()“和”getP_Counter()“和”setCapacity()“和”setType()“

這些錯誤是不言自明的。 您根本沒有為基本類型“Item”編碼這4種方法。


如果您正在尋找多態派生對象,即使用虛方法,那么您的虛方法(基類)不應該關注哪種派生類型。 基類成為派生類的接口定義。

即調用虛方法print()將調用派生類型的print()。


如果打印機具有PC不具備的方法(反之亦然),則有2種(或更多種)方法可以解決基類(Item)和派生類之間的“不匹配”問題。

我更喜歡為所有可能的派生方法提供基類方法。 所以我會將這四種方法添加到基類(全部標記為虛擬)

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

我也更喜歡基類方法來處理(可能是錯誤/警告消息)請求派生執行它不支持的方法的概念。 這種缺乏支持是由於在多重努力中“混合蘋果和橙子”。 (我經常看到這個。)

如果setCapacity()對派生類Foo沒有意義,

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

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

看看Foo中的虛方法如何將信息發送到基類方法?

對於派生類Bar,它具有設置容量:

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

也許更好的方法需要比計算機課更多的英語語言能力。 此方法要求您創建每個派生類可以支持的動詞。

典型的例子可能是類動物,衍生物種。 並非所有物種都可以吠叫,但也許你想要考慮的所有物種都可以發聲(),或者他們說話(),吃飯()或者另一端。

Dog :: vocalize(){bark();幾乎可以支持Animal :: vocalize(); },cat :: vocalize(){meow(); 其中樹皮和喵喵是物種(或派生類)的具體方法。

我猜不出你的意思是打印機:: setCapacity()或pc :: setCapacity()。 你需要定義它。 然后提出一個更加“通用”的動詞,即PC和打印​​機都支持。 也許這些辦公設備對象不應該解決這些問題。

查看您的多態教程。 仔細計划您的對象。

如果您可以改進它,請更新您的問題。

您可以統計或動態轉換該指針以了解他的示例類型:

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

動態轉換是昂貴的事情,你可能想要使用static_cast,如果你知道它是什么類型

auto e = static_pointer_cast<expecting type>(pointer);

例如:

auto e = static_pointer_cast<Pc>(pointer);

如果你正在使用原始指針,你想使用static_cast而不是static_pointer_cast

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM