我怎么知道指向基类对象的指针数组中元素的类型,它将为派生类分配内存

时间:2017-01-12 23:07:26

标签: c++ arrays class pointers inheritance

PCPrinter是来自基类Item的派生类,如果我创建一个类型为Item的指针数组,我想为数组分配内存根据用户的输入,它可以使数组中的元素为PC s或Printer 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;
}

5 个答案:

答案 0 :(得分: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];

答案 1 :(得分:0)

我想说这样做的正确方法是使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;

答案 2 :(得分: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或任何其他技术。

答案 3 :(得分:0)

问题不明确。也许它是:你为什么得到:

  

“错误:类”项目“没有成员”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和打印​​机都支持。也许这些办公设备对象不应该解决这些问题。

查看您的多态教程。仔细计划您的对象。

如果您可以改进它,请更新您的问题。

答案 4 :(得分:0)

您可以统计或动态转换该指针以了解他是什么类型 例如:

`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