2013-05-01 101 views
3

我试图子对象传递给方法任何子对象,但不知道输入对象的时间提前,除此之外,它会从父继承。 我可以将类型设置为父类,并且编译器很高兴,但是当此过程发生时,我会丢失子数据。C++通过与父类型的方法

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子数据丢失,只有父数据保持不变。

我已经看过成虚函数,动态绑定,“set”,但已成为完全搞不清我应该采取的方向。

可有人请让我回到正轨?

谢谢。

+0

发布您的实际代码,最好编译 – yngccc 2013-05-01 00:35:35

+0

“传递一个子对象的方法,但不知道输入对象提前” <是不是意味着类型是孩子???? – marcadian 2013-05-01 00:35:58

+0

@marcadian对象类型可以是大约4种继承类型中的任何一种,Child1,Child2等 – 2013-05-01 00:37:54

回答

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 */ 
    } 

    // ... 
} 

通过你的参数为指针的方法,你将需要至少有一个虚函数在你的班级为了这个工作。

2

由于维迪奇硼酸指出的那样,你有一个选择是使用动态演员。但是,对于一些编译器(如MSVC),使用动态强制转换可能会造成代价高昂,因此在评估指针时会运行字符串比较。

你有另一种选择是使用静态铸造。静态转换在编译时进行评估,因此几乎没有使用它们的成本。但是,您仍然必须有一种方法来确定您的类的类型,以便知道要将其转换为什么类型。在你的基类中,你可以有一个名为getType()的纯虚函数,它返回一个枚举值或一个无符号整数,表示该类的id。然后,您可以在“someOtherMethod”内部检查传入的类的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-> someOtherMethod(),其中someOtherMethod是您的孩子必须定义的纯虚函数。您可能会在多个方法定义中重复运行代码,在这种情况下,某些设计模式(如NVI模式)可能会派上用场。

2

如果孩子素显示或孩子采取行动,不会在父抽象所属的信息,那么你可以判断孩子是通过动态铸造或检查类型谁。然而,正如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); 
    } 
}; 

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