C++ 在基类指针传递参数时检查子类型

C++ 在基类指针传递参数时检查子类型,c++,C++,我有一个基本的B和它的两个派生类(D1,D2),看起来像这样 struct B { virtual B* DoSomething()=0; }; struct D1:public B { B* DoSomething() { // D1 does something return pD1; } }; struct D2:public B { B* DoSomething() { // D2 does something

我有一个基本的
B
和它的两个派生类(
D1
D2
),看起来像这样

struct B
{
   virtual B* DoSomething()=0;
};

struct D1:public B
{
   B* DoSomething()
   {
      // D1 does something
      return pD1;
   }
};

struct D2:public B
{
   B* DoSomething()
   {
     // D2 does something
     return pD2;
   }
};
现在我有了一个函数

void Init(B*pB)
{
   if(pB is D1)
   {
      D1* pD1=down_cast(pB);
      pD1->MethodD1();
   }
   else if(pB is D2)
   {
      D2* pD2=down_cast(pB);
      pD2->MethodD2();
   }
   else
   {
      //do something else
   }
}
我不想像这样在
Init()
方法中检查类型,但不知道还能做什么。

这是您的
Init()
方法,不在伪代码中:

void Init(B*pB)
{
   if(D1 *pD1 = dynamic_cast<D1*>(pB))
   {
      pD1->MethodD1();
   }
   else if(D2 *pD2 = dynamic_cast<D2*>(pB))
   {
      pD2->MethodD2();
   }
   else
   {
      //do something else
   }
}
void Init(B*pB)
{
如果(D1*pD1=动态_铸造(pB))
{
pD1->method1();
}
否则如果(D2*pD2=动态_铸造(pB))
{
pD2->method2();
}
其他的
{
//做点别的
}
}
如您所见,如果派生类的类型不是您要强制转换的类型,则动态强制转换返回
nullptr

您也可以使用引用来实现这一点,在这种情况下,如果类型不是您要强制转换的类型,则dynamic_cast将返回一个异常,因此,由于异常处理不是免费的,因此最好使用指针进行动态强制转换。 还请注意,这是一个运行时检查,而不是编译时检查。

这是您的
Init()
方法,不是伪代码:

void Init(B*pB)
{
   if(D1 *pD1 = dynamic_cast<D1*>(pB))
   {
      pD1->MethodD1();
   }
   else if(D2 *pD2 = dynamic_cast<D2*>(pB))
   {
      pD2->MethodD2();
   }
   else
   {
      //do something else
   }
}
void Init(B*pB)
{
如果(D1*pD1=动态_铸造(pB))
{
pD1->method1();
}
否则如果(D2*pD2=动态_铸造(pB))
{
pD2->method2();
}
其他的
{
//做点别的
}
}
如您所见,如果派生类的类型不是您要强制转换的类型,则动态强制转换返回
nullptr

您也可以使用引用来实现这一点,在这种情况下,如果类型不是您要强制转换的类型,则dynamic_cast将返回一个异常,因此,由于异常处理不是免费的,因此最好使用指针进行动态强制转换。
还请注意,这是一个运行时检查,而不是编译时检查。

您确实应该这样做

struct B
{
   virtual void Init();
   virtual B* DoSomething()=0;
};

struct D1:public B
{
   B* DoSomething()
   {
      // D1 does something
      return pD1;
   }
   void Init()
   {
      MethodD1();
   }

};


struct D2:public B
{
   B* DoSomething()
   {
      // D2 does something
      return pD2;
   }
   void Init()
   {
      MethodD2();
   }

};
在你的主代码中

void Init(B*pB)
{
   pB->Init();
}

这就是封装、继承、虚拟方法等的全部要点。

您确实应该这样做

struct B
{
   virtual void Init();
   virtual B* DoSomething()=0;
};

struct D1:public B
{
   B* DoSomething()
   {
      // D1 does something
      return pD1;
   }
   void Init()
   {
      MethodD1();
   }

};


struct D2:public B
{
   B* DoSomething()
   {
      // D2 does something
      return pD2;
   }
   void Init()
   {
      MethodD2();
   }

};
在你的主代码中

void Init(B*pB)
{
   pB->Init();
}

这就是封装、继承、虚拟方法等的全部要点。

method1
method2
B
中的方法相同,并且
D1
D2
都覆盖它们,怎么样?如果你真的想明确地发送,你的答案是
dynamic\u cast
。你是在寻找还是?也许你想查看typeid是个不好的建议。正确的解决方案是正确使用虚方法。@昆汀:虚方法的问题是Init()接收到一个B*。因此,它无法区分哪个类重写了方法D1或D2,让
MethodD1
MethodD2
B
中的方法相同,让
D1
D2
都重写如何?如果你真的想明确地发送,你的答案是
dynamic\u cast
。你是在寻找还是?也许你想查看typeid是个不好的建议。正确的解决方案是正确使用虚方法。@昆汀:虚方法的问题是Init()接收到一个B*。所以它无法分辨哪个类重写了方法,D1或D2