【问题标题】:Array of Pointers to an Abstract Class: to nullptr or not to nullptr (C++)指向抽象类的指针数组:指向 nullptr 或不指向 nullptr (C++)
【发布时间】:2019-09-23 01:41:06
【问题描述】:

我想遍历一个指向抽象类的指针数组以找到一个“空”槽,即检查一个元素是否指向派生类的对象。我的方法是创建数组并将每个元素设置为 nullptr。然后,我可以检查元素是否为 nullptr。

这可行,但有更好的方法吗? 编辑:我可以检查指向抽象类的指针数组中的第一个“空”元素(其中派生类将定期构造并由数组指向,呈现该元素不是“空”),而不分配每个元素在设置数组时设置 nullptr,然后检查 nullptr 作为检查元素是否“空”的一种方式?换句话说,我可以直接检查元素是否指向构造的基类吗?

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

我想知道是否有更简单的方法来执行此操作,即检查指向抽象类的指针数组中的元素是指向派生类的对象还是只是抽象指针,而不将元素设置为 nullptr。比如,标准库中有 bool IsObject(ObjectType* ptr) 之类的吗?

而且,我想知道将每个元素设置为 nullptr 是否会带来任何潜在问题,除了循环遍历数组并将元素设置为 nullptr 的计算成本。

【问题讨论】:

  • 那是什么?你想找到空白点(nullptr 是绝对合理的)还是找出指针是否指向特定类的对象(你会使用类似if(dynamic_cast&lt;Cat*&gt;(catArray[i])) 的东西)?
  • 您可以存储一个size_t,指示最后一个Cat 的存储位置。或者您可以使用std::vector 或任何其他标准容器代替数组。甚至你也可以使用 std::optional 来解决这些问题。
  • 您的设置中没有“抽象指针”之类的东西。你能描述一下你所说的那句话是什么意思吗?此外,如果一个元素没有被设置为一个值,那么检查它的值是未定义的行为。 (这就是为什么指针应该始终设置为某个值的原因;nullptr 值带有“我不指向任何东西”的语义。)
  • 有什么理由不使用std::vector&lt;Cat*&gt; 吗?或者更好的是std::vector&lt;std::unique_ptr&lt;Cat&gt;&gt;
  • Cat*[i] = nullptr; 是一个语法错误,它肯定不会“工作”

标签: c++ arrays pointers abstract-class nullptr


【解决方案1】:

您必须使用 dynamic_cast 将基类指针转换为派生类指针。 dynamic_cast 执行类型安全向下转换。

如果 dynamic_cast 的结果不是 nullptr 则表示转换成功。否则无法从指针中获取派生类指针。

你必须这样做:

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

其中 catArray 是基类指针数组。

更新

我认为创建一个真正的猫对象数组存在错误:

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

既然您将所有数组元素初始化为 nullptr,您肯定需要检查 == nullptr 吗?我认为您需要进行以下更改:

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

【讨论】:

  • 谢谢,jignatius!我要去看看这个!
  • 我无法使用 dynamic_cast 产生我想要的结果。我需要检查指针是否指向构造对象。
  • 谢谢!你说得对。是的,这是我在尝试从我正在处理的实际代码中删除示例代码时将错误放入示例代码的另一种情况。在上面修复它。
【解决方案2】:

我猜想其他使用dynamic_cast 的更简单的方法是使用std::vector 而不是原始指针。

示例代码

#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

现代版本,使用智能指针。

#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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多