当前位置:  开发笔记 > 编程语言 > 正文

如何检查对象的类型是否是C++中的特定子类?

如何解决《如何检查对象的类型是否是C++中的特定子类?》经验,为你挑选了4个好方法。

我正在考虑使用typeid()但我不知道如何询问该类型是否是另一个类的子类(顺便说一下,它是抽象的)



1> Martin York..:

 

class Base
{
  public: virtual ~Base() {}
};

class D1: public Base {};

class D2: public Base {};

int main(int argc,char* argv[]);
{
  D1   d1;
  D2   d2;

  Base*  x = (argc > 2)?&d1:&d2;

  if (dynamic_cast(x) == nullptr)
  {
    std::cout << "NOT A D2" << std::endl;
  }
  if (dynamic_cast(x) == nullptr)
  {
    std::cout << "NOT A D1" << std::endl;
  }
}


@krlmlr.你能在编译时告诉`x`的类型吗?如果是这样,那么`static_cast <>()`就行了.如果在运行时之前无法告诉`x`的类型,那么你需要`dynamic_cast <>()`

2> Dima..:

你真的不应该.如果您的程序需要知道对象是什么类,那通常表明存在设计缺陷.看看您是否可以使用虚拟功能获得所需的行为.此外,有关您尝试做什么的更多信息将有所帮助.

我假设你有这样的情况:

class Base;
class A : public Base {...};
class B : public Base {...};

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

如果这是你所拥有的,那么尝试做这样的事情:

class Base
{
  virtual void bar() = 0;
};

class A : public Base
{
  void bar() {/* do X */}
};

class B : public Base
{
  void bar() {/* do Y */}
};

void foo(Base *p)
{
  p->bar();
}

编辑:由于关于这个答案的辩论在这么多年后仍然存在,我想我应该引用一些参考文献.如果你有一个指针或对基类的引用,并且你的代码需要知道对象的派生类,那么它违反了Liskov替换原则.鲍勃叔叔称之为" 面向对象设计的诅咒 ".


是的 - 这一切都很好 - 但这家伙想知道如何解决类型
+1.我认为这个名字的正确名称是"告诉,不要问".基本上,总是喜欢多态性(告诉对象做什么,让实现处理它)在case/if语句中你要求找出你正在处理的对象类型.
虽然正确,但这并不能回答这个问题.
@Dima曾经使用过定义超类的外部库吗?请尝试在那里应用你的答案.
这个答案使得你可以控制你需要转换的类型并且可以重写它们的相当大的假设...例如我正在基于另一个GUI库向GUI库添加一个功能,我需要知道窗口小部件的父级是否可滚动.原始库无法测试这个,所以我必须尝试将我的小部件父级转换为可滚动小部件的基类,这真的很糟糕.无论如何,关键是你遗漏了手头问题的*实际*答案.
@Dima,如果有人想知道语法仅仅是为了学习目的(假设他们正在阅读一本用Java编写的书,关于设计缺陷,他们需要将其转换为C++),该怎么办?
执行此操作(至少在Java中)的常见用例是比较两个对象是否相等.通常,您需要在检查所需的相等属性之前检查它们是否属于同一子类.
这只是您的个人意见,没有冒犯.相反,我认为在必要时将超类型转换为派生类没有任何问题.实际上,这是OOP使用的很大一部分 - 通过一些通用流程来管理类似的数据,但最终还是单独处理它们.
@TomášZato,您当然可以找到您可能想知道对象的实际类型的情况.然而,这仍然意味着你正在与语言作斗争,并且存在潜在的设计缺陷.这个漏洞可能存在于第三方库中,但它仍然是一个缺陷.如果你无法控制它,那么你必须忍受它.如果你有控制权,那么你应该考虑修复底层设计.
@TomášZato,这不仅仅是我个人的观点.如果您需要知道对象的派生类型,那么您的设计违反了Liskov替换原则:https://en.wikipedia.org/wiki/Liskov_substitution_principle这是Robert C. Martin的一篇论文,他在那里专门讨论了为什么要求因为对象的类型违反了LSP,为什么它是"面向对象设计的诅咒":http://www.objectment.com/resources/articles/lsp.pdf
@Dima对于生产代码,我同意你的看法.但工厂的工作是根据其输入制作正确的子类.通过验证子类的属性是否与输入一致,可以一起测试工厂*和*每个子类*.但如果有一个错误,那么这样的测试将无法帮助任何人判断问题是在工厂还是在它构建的子类中.验证子类的类型是在这些测试中实现分离的一种方法.

3> Drew Hall..:

你可以这样做dynamic_cast(至少对于多态类型).

实际上,在第二个想法 - 你不能告诉它是否特定类型与 - dynamic_cast但你可以告诉它是否是那种类型或其任何子类.

template 
bool IsType(const SrcType* src)
{
  return dynamic_cast(src) != nullptr;
}


@OllieFord:当没有任何虚函数时.
啊哦 谢谢。

4> coppro..:

dynamic_cast可以确定类型是否包含继承层次结构中任何位置的目标类型(是的,它是一个鲜为人知的特性,如果B继承自AC,它可以A*直接转换为a C*).typeid()可以确定对象的确切类型.但是,这两者都应该非常谨慎地使用.如前所述,您应始终避免动态类型识别,因为它表明存在设计缺陷.(另外,如果你知道对象是为确保目标的类型,你可以做一个垂头丧气了static_cast.加速提供了一个polymorphic_downcast会做一个沮丧的用dynamic_castassert在调试模式下,并在释放模式将只使用一个static_cast).

推荐阅读
谢谢巷议
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有