简体   繁体   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

PC and Printer are derived classes from the base class Item , if I make an array of pointers of type Item , and I wanna allocate memory for the array based on the user's input so it can make the elements in the array either PC s or Printer s or a mix of them. PCPrinter是基类Item派生类,如果我创建一个Item类型的指针数组,我想根据用户的输入为数组分配内存,这样它就可以使数组中的元素成为PCPrinter s或它们的混合。

all the errors are the same: 所有错误都是一样的:

ERROR: class "Item" has no member "getPC_Counter()" and "getP_Counter()" and "setCapacity()" and "setType()" 错误:类“Item”没有成员“getPC_Counter()”和“getP_Counter()”和“setCapacity()”和“setType()”

Sorry for asking my question in a very weird and complicated manner but i don't really know how to explain my question properly, any ways here's my code and i'll try to explain what i can't figure out in the comments: 很抱歉以非常奇怪和复杂的方式提出我的问题,但我真的不知道如何正确解释我的问题,这里的任何方式都是我的代码,我将尝试解释我在评论中无法弄清楚的内容:

#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;
}

You need to use dynamic_cast to cast your base pointer down to the derived pointer you require. 您需要使用dynamic_cast将基指针向下转换为所需的派生指针。 For example, in the case of PC : 例如,在PC的情况下:

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

will work, as this casts Item* (the base) down to a PC* (the derived). 将工作,因为这将Item* (基础)下放到PC* (派生的)。

Note, as this is C++, you should really be using std::unique_ptr and std::vector instead of raw-pointers and C-style arrays, respectively. 注意,因为这是C ++,你应该分别使用std::unique_ptrstd::vector而不是原始指针和C风格的数组。 The former will still allow dynamic casting and polymorphism. 前者仍然允许动态转换和多态。 In other words, use: 换句话说,使用:

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

instead of 代替

Item* store[5];

I would say the correct way to do this is to make getP_Counter and getPC_Counter static member functions. 我想说这样做的正确方法是使getP_CountergetPC_Counter静态成员函数。 Then there is no requirement for dynamic dispatch, as those functions only access static data anyway. 然后不需要动态调度,因为这些函数无论如何只访问静态数据。

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

To deal with setCapacity and setType simply delay erasing the type by initially assigning to the real type and add this to the array after calling those functions. 处理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;

A common pattern to solve the issue is known as double dispatching. 解决该问题的常见模式称为双重调度。
It follows a minimal, working example: 它遵循一个最小的工作示例:

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);
}

The basic idea is that you can use a visitor class that is accepted by all of the classes that belong to your hierarchy. 基本思想是您可以使用属于您的层次结构的所有类都接受的访问者类。
When a class in the hierarchy accepts a visitor, it promotes itself to the right type and pass a reference to the visitor. 当层次结构中的某个类接受访问者时,它会将自己提升为正确的类型并将引用传递给访问者。

It's heavily based on polymorphism and pretty invasive as a solution, but it doesn't require you to use dynamic_cast or any other technique. 它主要基于多态性和非常具有侵入性的解决方案,但它不要求您使用dynamic_cast或任何其他技术。

The Question is not clear. 问题不明确。 Perhaps it is: Why do you get: 也许它是:你为什么得到:

"ERROR: class "Item" has no member "getPC_Counter()" and "getP_Counter()" and "setCapacity()" and "setType()" “错误:类”项“没有成员”getPC_Counter()“和”getP_Counter()“和”setCapacity()“和”setType()“

These errors are self explanatory. 这些错误是不言自明的。 You simply have not coded these 4 methods for the base type "Item". 您根本没有为基本类型“Item”编码这4种方法。


If you are headed for polymorphic derived objects, ie using virtual methods, your virtual methods (of base class) should not care which type of derived. 如果您正在寻找多态派生对象,即使用虚方法,那么您的虚方法(基类)不应该关注哪种派生类型。 The base class becomes an interface definition for the derived classes. 基类成为派生类的接口定义。

ie Invoking the virtual method print() will invoke the derived type's print(). 即调用虚方法print()将调用派生类型的print()。


If a printer has methods that a PC does not (or vice versa) there are 2 (or more) approaches to resolve this 'mis-match' between base class (Item) and the derived classes. 如果打印机具有PC不具备的方法(反之亦然),则有2种(或更多种)方法可以解决基类(Item)和派生类之间的“不匹配”问题。

I prefer to have base class methods for all possible derived methods. 我更喜欢为所有可能的派生方法提供基类方法。 So I would add the four methods to base class (all marked as virtual) 所以我会将这四种方法添加到基类(全部标记为虚拟)

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

I also prefer for the base class methods to handle (perhaps an error / warning message) the concept of asking a derived to perform a method that it does not support. 我也更喜欢基类方法来处理(可能是错误/警告消息)请求派生执行它不支持的方法的概念。 This lack of support is caused by 'mixing apples an oranges' in a polymorhpic effort. 这种缺乏支持是由于在多重努力中“混合苹果和橙子”。 (I've seen this quite often.) (我经常看到这个。)

If setCapacity() is meaningless for derived class Foo, 如果setCapacity()对派生类Foo没有意义,

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

and

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

See how the virtual method in Foo sent info up to the base class method? 看看Foo中的虚方法如何将信息发送到基类方法?

And for a derived class Bar, which does have a capacity to set: 对于派生类Bar,它具有设置容量:

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

Perhaps a better approach requires more English language ability than is taught in computer class. 也许更好的方法需要比计算机课更多的英语语言能力。 This approach requires that you create a verb that each derived class can support. 此方法要求您创建每个派生类可以支持的动词。

The classic example is perhaps class animal, with derived species. 典型的例子可能是类动物,衍生物种。 Not all species can bark, but maybe all the ones you wish to consider can vocalize(), or perhaps they speak(), or eat() or, well the other end. 并非所有物种都可以吠叫,但也许你想要考虑的所有物种都可以发声(),或者他们说话(),吃饭()或者另一端。

Animal::vocalize() can be virtually supported by dog::vocalize() { bark(); Dog :: vocalize(){bark();几乎可以支持Animal :: vocalize(); }, cat::vocalize() { meow(); },cat :: vocalize(){meow(); }, where bark and meow are species (or derived class) specific methods. 其中树皮和喵喵是物种(或派生类)的具体方法。

I can not guess what you would mean by printer::setCapacity(), or pc::setCapacity(). 我猜不出你的意思是打印机:: setCapacity()或pc :: setCapacity()。 You need to define it. 你需要定义它。 And then come up with a more 'generic' verb that both pc and printer support. 然后提出一个更加“通用”的动词,即PC和打印​​机都支持。 And maybe these office equipment objects should not address these issues. 也许这些办公设备对象不应该解决这些问题。

Review your polymorphic tutorials. 查看您的多态教程。 Plan your objects carefully. 仔细计划您的对象。

Update your question when you can improve it. 如果您可以改进它,请更新您的问题。

You can statistically or dynamically cast that pointer to know what type he is example : 您可以统计或动态转换该指针以了解他的示例类型:

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

dynamic cast are expensive thing and you probably want to use static_cast if u know what type is it 动态转换是昂贵的事情,你可能想要使用static_cast,如果你知道它是什么类型

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

example : 例如:

auto e = static_pointer_cast<Pc>(pointer);

also if u are using raw pointers you want to use static_cast instead of static_pointer_cast 如果你正在使用原始指针,你想使用static_cast而不是static_pointer_cast

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 基本指针如何能够知道派生类实例中基本成员的内存位置? - How are base pointers able to know the memory location of base members in a derived class instance? 为什么我不能使用指向派生类指针的基类类型分配内存? - Why i cannot allocate a a memory using a a base class type pointing to a derived class pointer? 如何在CUDA中为我的指针数组分配设备内存? - How do I allocate device memory to my array of pointers, in CUDA? 如何使用malloc通过基类的指针为派生类的对象分配内存? - How to allocate memory for object of the derived class by pointer of the base class using malloc? 可以将派生对象指针存储在基类指针数组中吗? - Can derived object pointers be stored in an array of base class pointers? 指向包含派生类对象和重载&lt;&lt;运算符的基类的指针数组 - Array of pointers to the base class that contains objects of derived classes and overloaded << operator 如何读取指向派生类的基类指针数组的内存布局 - How to read memory layout of an array of base class pointers pointing to derived class 您如何管理指向在派生类中都扩展的基类的指针? - How do you manage pointers to base classes that are both extended in a derived class? 如何在基础构造函数中分配基于派生类的大小的数组? - How to allocate array in base constructor with size based on derived class? 为什么使用基类指针来派生类 - Why use base class pointers for derived classes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM