c ++将父类型的任何子对象传递给方法

时间:2013-05-01 00:34:17

标签: c++ object dynamic binding virtual

我正在尝试将子对象传递给方法,但不提前知道对象类型,除了它将从父级继承。 我可以将类型设置为父类,编译器很高兴,但是当这个过程发生时我会丢失子数据。

class Parent{
public:
Parent(int val);
};

class Child{
public:
Child(double childval, int parentval)
};

Child::Child(double childval, int parentval) : Parent(parentval)

Child childObj = new Child(cval, pval);

int someOtherMethod(Parent pobj);
someOtherMethod(childObj);  // Looses child data but parent data persists. How to keep child data too?

很好,但如果我将childObj传递给someOtherMethod,子数据就会丢失,只保留父数据。

我已经研究过虚拟函数,动态绑定,“设置”,但我对我应该采取的方向感到十分困惑。

有人可以让我回到正轨吗?

感谢。

3 个答案:

答案 0 :(得分:2)

正如Nemanja Boric所指出的,你有一个选择就是使用动态演员。但是,在某些编译器(例如MSVC)上使用动态强制转换可能会很昂贵,MSVC会在评估指针时运行字符串比较。

您拥有的另一个选择是使用静态强制转换。静态强制转换在编译时进行评估,因此使用它们几乎没有任何成本。但是,您仍然需要有一种方法来识别您的类的类型,以便知道将其转换为什么。在您的基类中,您可以使用名为getType()的纯虚方法,该方法返回枚举值或表示类的id的无符号整数。然后你可以在'someOtherMethod'里面检查传入的类的id是什么类型的id,然后对这种类进行强制转换。

E.g。

在某个文件中定义的是带有类型

的枚举
enum ClassTypes
{
    ClassType1,
    ClassType2,
    ...
};

作为旁注:如果你没有改变pObj指向你想要制作指针的东西 常量。它让读者知道你不打算任何人改变它,它也是 一种针对你最大的敌人(你自己)的防御编程形式,确保你不会意外地改变它,然后尝试对其进行施法。

int someOtherMethod(Parent * const pObj)
{
    if(pObj == NULL)
        return 0;

    switch(pObj->getType())
    {
        case ClassType1:
        {
            Class1 * const pClass = static_cast<Class1*>(pObj);
            //Do stuff to class type 1
            break;
        }
        case ClassType2:
        {
            Class2 * const pClass = static_cast<Class2*>(pObj);
            break;
        }
    };

    return 1;
}

正如您所看到的,虽然这可能会非常快速地增长,但它并不能很好地处理重复的代码。此外,Static Cast可能很危险,因为在运行时没有检查是否有可能导致崩溃。

你必须考虑类本身的设计。也许你希望在这个函数中执行的一些代码可以在类本身中执行。因此,您不必知道类型,而只需说:

pObj-&gt; someOtherMethod(),其中someOtherMethod是您的所有孩子必须定义的纯虚函数。您可能会再次遇到多个方法定义的重复代码,在这种情况下,某些设计模式(如NVI模式)可能会派上用场。

答案 1 :(得分:2)

如果Child提出的信息或孩子采取的行动不属于Parent抽象,那么您可以通过动态投射或检查类型来确定孩子是谁。然而,正如Edward Corlew所说,这有一些缺点。

或者,您可以通过双重发送询问孩子。这可以通过将对象传递给子进程然后子进程选择它的类型来完成。然后访问者可以收集所需的任何信息。

class Child1;
class Child2;

class Visitor
{
public:
  void DoStuff(Child1 & child1);
  void DoStuff(Child2 & child2);
};

class Parent
{
public:
  void DoStuff(Visitor & visitor);
};

class Child1 : public Parent
{
public:
  void DoStuff(Visitor & visitor)
  {
    visitor.DoStuff(*this);
  }
};

class Child2 : public Parent
{
public:
  void DoStuff(Visitor & visitor)
  {
    visitor.DoStuff(*this);
  }
};

潜在地,访问者本身可能来自并允许不同的操作。这消除了在整个程序中传播类型检查的需要。但是,访问者类本身与派生的子代相关联,需要在添加具体子代时进行更新。

答案 2 :(得分:1)

明智地设计类,使用多态和定义良好的接口从子类中获取数据。

但是,如果您需要在C ++中进行向下转换,则可以使用dynamic_cast<T>执行此操作:

int someOtherMethod(Parent *pobj);
{
    Child1 *c1;
    Child2 *c2; 
    Child3 *c3;
    Child4 *c4;



    if((c1= dynamic_cast<Child1*>(pobj)) != 0)
    {
         /* Do stuff here, pobj is instance of Child1 */
    }
    else if((c2 = dynamic_cast<Child2*>(pobj)) != 0))
    {
       /* Do stuff here, pobj is instance of Child2 */ 
    }

    // ...
}

将参数作为指向方法的指针传递,并且您需要在类中至少有一个虚函数才能使其正常工作。