【问题标题】:C++ how to check if two clsses are from the same objectC++如何检查两个类是否来自同一个对象
【发布时间】:2013-07-29 19:28:19
【问题描述】:

在准备考试的时候遇到这个问题,希望有一个简短的解释。
如果我有一个class Object 和另一个:class Point : public Object
现在,如果我得到 Object& O1Object& O2 ,但 Object 也可以是 Point ...
所以我的主要问题是如何检查它们是否都是Point 因为我需要访问Object 没有的字段

这是两个类:

类对象 {
public :
一些功能
};

类点:公共对象{
双x;
双 y;
public:
相同的功能不同的实现
};

我想访问 x,y 但我需要先确保它是 Point

提前致谢

【问题讨论】:

  • Object 永远不能是 PointObject& 可以是 Point&(与(智能)指针相同)。
  • 有没有办法确保我正在处理一个点而不是一个对象?我编辑了一个问题,我得到了 Object& O1...
  • dynamic_cast<Point*>(ptr) 你在找什么...
  • 通常您不需要也不应该这样做。您可能需要Object 中的虚拟方法。弄清楚你为什么需要 x,y 并给它起个名字。

标签: c++ class inheritance c++11


【解决方案1】:

你可以使用 dynamic_cast

Object &o = ...;
if(Point *p = dynamic_cast<Point*>(&o)) {
  // ...
}

如果o 的动态类型是Point 或派生自它,则if 中的代码将在p 随时可用的情况下执行(o 的静态类型是Object )。

如果你已经知道它是Point,你可以使用引用

Point &p = dynamic_cast<Point&>(o);
// ...

为此,Object 中必须至少有一个 virtual 函数(如果只有析构函数)。

【讨论】:

  • @NadavPeled 不一定,如果您碰巧再次从 Point 派生。但这更准确地取决于您想要做什么。通常,如果对象“is-a Point”就足够了,并且您通常不想要“is-a Pointis-不是一个 SuperGoodPoint"
  • 我明白了,所以你是说如果我知道等式的一部分是一个点,typeid 就可以了,但更一般和正确的检查方法是使用动态投?
【解决方案2】:

这可能很草率,但如果你有一个对象的指针或引用,你总是可以调用一个 dynamic_cast。如果指针作为 nullptr 返回,那么您知道您的对象不是所需对象的派生类。

class CBase { 
      virtual void dummy(){}
};
class CDerived: public CBase {
    int a;
};

int main () {
  try {
    CBase * pba = new CDerived;
    CBase * pbb = new CBase;
    CDerived * pd;

    pd = dynamic_cast<CDerived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast" << endl;

    pd = dynamic_cast<CDerived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast" << endl;

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}

【讨论】:

  • 我认为你的意思是“如果指针返回为 0”,因为 dynamic_cast 失败时返回 0。
  • 您能否解释一下在尝试将对象投射到点时动态投射会如何失败?
  • 并且还要解释这可能是一个糟糕的设计——是的,有些情况你真的需要这样做——但是自从我开始专业使用 C++ 以来的 10 年里,我只见过在少数地方(我能想到的 3-4 个)执行此操作的代码。
  • @Nadav Peled 把它想象成一个正方形和一个矩形。正方形是矩形,但并非所有矩形都是正方形。在这种情况下,点是对象,但并非所有对象都是点。所以会返回一个 nullptr
【解决方案3】:

一般来说,如果你“需要”知道这一点,那你就做错了。有一些例外,但通常,您不需要知道您正在“使用”哪种类型的对象。您的不同函数应声明为virtual,以便使用Object 执行操作的代码可以在对象是Point 类型对象时调用Point 中的相关函数。

如果你想访问xy,你应该通过一个虚函数间接地做到这一点,该虚函数执行需要对xy 执行的任何操作。如果你真的需要接触xy,而你只有(引用或指针)Object,那你就错了。

【讨论】:

  • 是的,当然,正如上面所写,我正在准备测试,它是关于我们需要了解某些代码行为的材料的一些“干”问题的一部分。
【解决方案4】:

您可以依赖 C++ 标准库提供的类型信息。以下示例摘自 cppreference.com:

#include <iostream>
#include <typeinfo>
#include <string>
#include <utility>

class person
{
  public:

   person(std::string&& n) : _name(n) {}
   virtual const std::string& name() const{ return _name; }

  private:

    std::string _name;
};

class employee : public person
{
   public:

     employee(std::string&& n, std::string&& p) :
         person(std::move(n)), _profession(std::move(p)) {}

     const std::string& profession() const { return _profession; }

   private:

     std::string _profession;
};

void somefunc(const person& p)
{
   if(typeid(employee) == typeid(p))
   {
      std::cout << p.name() << " is an employee ";
      auto& emp = dynamic_cast<const employee&>(p);
      std::cout << "who works in " << emp.profession() << '\n';
   }
}

int main()
{
   employee paul("Paul","Economics");
   somefunc(paul);
}

【讨论】:

  • 嗯,但你可以拥有class manager: public employee - 经理是employee 吗?不,但manager 具有employee 的所有属性,但也有一些额外内容(例如,他的经理是什么/谁),这些不会出现在employee 中。
  • 如果经理不是员工,那么它不应该从员工继承(继承是为了模拟“is-a”关系)。
  • 是的,我的意思是 manager "is-a" employee,但 typeid(employee) 不等于 manager,因此该方法在那个案子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 2016-01-24
  • 1970-01-01
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多