Array of Pointers to an Abstract Class: to nullptr or not to nullptr (C++)

若如初见. 提交于 2020-01-06 04:43:06

问题


I want to loop through an array of pointers to an abstract class to find an "empty" slot, that is to check whether an element points to an object of a derived class or not. My approach is to create the array and set each element to nullptr. Then, I can check if the element is nullptr.

This works, but is there a better way? Edit: Can I check for the first "empty" element in the array of pointers to an abstract class (in which derived classes will periodically be constructed and pointed to by the array, rendering that element not "empty"), without assigning each element to nullptr upon setting up the array and then checking for nullptr as a way to check if the element is "empty"? In other words, can I directly check whether the element points to a constructed base class or not?

Cat** catArray = new Cat*[200];
for(int i = 0; i < 200; i++){
   catArray[i] = nullptr;
}

for(int i = 0; i < 200; i++){
   if(catArray[i] == nullptr){ //edited, was typo as "!="
      AddRealCat(...);
      break;
   }
}      

I wonder if there's an easier way to do this, to check whether an element in an array of pointers to an abstract class points to an object of a derived class or is just an abstract pointer, without setting the element to nullptr. Like, is there a bool IsObject(ObjectType* ptr) or something in the standard library?

And, I wonder if setting each element to nullptr poses any potential problems, other than the computing cost of looping through the array and setting the elements to nullptr.


回答1:


You would have to use dynamic_cast to cast a base class pointer to a derived class pointer. dynamic_cast performs type safe down casting.

If the result of dynamic_cast is not nullptr then the cast has been successful. Otherwise no derived class pointer can be obtained from the pointer.

You would have to do like this:

Cat *pCat = dynamic_cast<Cat*>(catArray[i]);
if (pCat)
{
    AddRealCat(...);
    break;
}

where catArray is an array of base class pointers.

Update

I think there's an error with creating an array of real cat objects:

for(int i = 0; i < 200; i++){
   if(catArray[i] != nullptr){
      AddRealCat(...);
      break;
   }
}

Surely you need to check == nullptr since you initialising all array elements to nullptr? I think you need to make the following change:

for(int i = 0; i < 200; i++){
   if(catArray[i] == nullptr){
      catArray[i] = new RealCat();
      break;
   }
}    



回答2:


I guess the real easier way to do that other using dynamic_cast is using std::vector instead of a raw pointer.

Sample code

#include <string>
#include <iostream>
#include <vector>

struct Cat{
    virtual ~Cat() = default;
    virtual void meow() const = 0;
};

struct Meow : Cat{
    void meow() const override{ std::cout << "meow" << std::endl; }
};

int main()
{
    std::vector<Cat*> vec{100};
    vec[1] = new Meow();

    for(auto c : vec){
        if(auto m = dynamic_cast<Meow*>(c)){
            m->meow();
        }
    }

    // don't forget to release memory
    for(auto c : vec){
        delete c;
    }
}

Live Example

Modern version, using smart pointers.

#include <string>
#include <iostream>
#include <vector>
#include <memory>

struct Cat{
    virtual ~Cat() = default;
    virtual void meow() const = 0;
};
struct Meow : Cat{
    void meow() const override{ std::cout << "meow" << std::endl; }
};

int main()
{
    std::vector<std::unique_ptr<Cat>> vec{100};
    vec[1] = std::make_unique<Meow>();

    for(auto&& c : vec){
        if(auto m = dynamic_cast<Meow*>(c.get())){
            m->meow();
        }
    }

    // you don't need to manually clear the memory.
}

Live Example



来源:https://stackoverflow.com/questions/58054740/array-of-pointers-to-an-abstract-class-to-nullptr-or-not-to-nullptr-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!