我正在尝试将子对象传递给方法,但不提前知道对象类型,除了它将从父级继承。 我可以将类型设置为父类,编译器很高兴,但是当这个过程发生时我会丢失子数据。
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,子数据就会丢失,只保留父数据。
我已经研究过虚拟函数,动态绑定,“设置”,但我对我应该采取的方向感到十分困惑。
有人可以让我回到正轨吗?
感谢。
答案 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 */
}
// ...
}
将参数作为指向方法的指针传递,并且您需要在类中至少有一个虚函数才能使其正常工作。