【问题标题】:Determinate an object type in c++在 C++ 中确定对象类型
【发布时间】:2018-02-24 16:17:20
【问题描述】:

假设我有两个类映射两个具有相同接口的对象

class FirstChild : class Father
{
    //some fields and methods useful for class A
}

class SecondChild : class Father
{
   //some fields and methods useful for class B
}

稍后,在代码中完成了类似的操作

Father* myInstance = new SecondChild();

现在,如果我想知道对象的 type 以便在实例是 FirstChild 或 SecondChild 时必须执行一些操作,我正在做类似的事情:

if (typeid (myInstance) == typeid (FirstChild))
{
     // do stuff
} else if (typeid (myInstance) == typeid (SecondChild))
       {
            // do other stuff
       }

这是正确的做法吗? 因为在StackOverflow 的某个地方我读到typeid 不安全,添加一个虚函数更方便,比如说getType,然后在FirstChild 中做

char* getType { return "FirstChild"; }

说实话,我不太喜欢这种解决方案,因为它似乎绕过了面向对象编程中强大的多态性。

那么,各位,你们怎么看?在 C++ 中检查子对象类型的最佳方法是什么?

【问题讨论】:

  • dynamic_cast 可能吗?无论如何,这样做的必要性表明你有一个严重的设计缺陷。
  • 如果您需要知道类型,您可能做错了。
  • 这听起来像是你应该用多态性和虚函数来解决的问题。也许dynamic_cast.
  • 虽然这并没有错,但这是(非常)旧的做事方式,除非您正在开发 C++ 插件。不要这样做,重新考虑你的设计。
  • 面向对象的解决方案将使用虚函数来执行特定于类的逻辑,如果您要使用整数值,请不要使用 if-else if-else-if....使用 case 语句,虽然大多数优秀的编译器会优化你的 if-else 列表,但 case 会更容易阅读。

标签: c++ oop types casting type-conversion


【解决方案1】:

有几种方法可以做到这一点。

typeiddynamic_cast<> 是执行此操作的“官方方式”。

FirstChild *fptr = dynamic_cast<FirstChild>(myInstance);
if (fptr) {
  // do something
} else {
  SecondChild *cptr = dynamic_cast<SecondChild>(myInstance);
  if(cptr) {
     // do something else, and so on...
  }
}

但这并不是最优雅的方式。

另一种等效方式是使用“id 类型”,例如枚举或类似的。

但正如许多人所说,如果您需要知道类型是什么,那么您可能做错了。

一个明显的替代方法是让对象执行特定操作。假设您在 activate() 函数中使用此代码。为什么不使用虚拟doAction()

class Father {
   public:
      virtual void doAction() = 0;
}

//...
myInstance->doAction();

使用不同的设计模式有不同的变化。但我想你明白了。

【讨论】:

    【解决方案2】:

    一个简单的方法是使用dynamic_cast。示例:

    Father *myInstance = new SecondChild();
    SecondChild *casted = dynamic_cast<SecondChild*>(myInstance);
    if (casted != nullptr)
        std::cout << "myInstance is a SecondChild!";
    else 
        std::cout << "myInstance is not a SecondChild!";
    

    发件人:cppreference: dynamic cast

    如果转换成功,dynamic_cast 返回一个 new_type 类型的值。如果转换失败并且 new_type 是指针类型,则返回该类型的空指针。如果转换失败并且 new_type 是一个引用类型,它会抛出一个与 std::bad_cast 类型的处理程序匹配的异常。

    正如@Rob 所指出的,您可以使用虚函数并让对象自己执行操作。

    struct Father 
    {
        virtual void process() = 0;
    };
    

    您可以使用虚函数来决定是否应该执行操作,而不是检查类型。

    struct Father 
    {
        virtual bool shouldProcess() { return false; }
    };
    struct SecondChild : Father
    {
        bool shouldProcess() override { return true; }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-14
      • 1970-01-01
      • 2013-11-25
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 1970-01-01
      • 2016-09-06
      相关资源
      最近更新 更多