显式切片派生对象

时间:2013-01-25 20:30:09

标签: c++ inheritance casting static object-slicing

我为我公司建立的项目有一些类结构。在某些时候,我已经看到派生对象的“通常不需要的”切片实际上可以使我的代码有效。请注意:

class Base {
  private:
    int myType; //some constant here
  public:
    Base(): myType(1)
    { 
       if(someTest()) 
       { 
         myTest = 0; // signifies that this object is not working well for me
       }  // if the test succeeds, now I know this is a TYPE1 object
    }

    virtual bool someTest() { /* does make some validation tests */ } 
    int GetMyType() { return myType; }

    // some more virtual functions follow
}

class Derived: public Base {
  public:
    Derived() : Base() 
    { 
      if( someTest() /*calls the derived*/ ) 
      { 
        myType =2; // signifies that this is a TYPE2 object
        /* Do something more*/ 
      }  
    }

    virtual bool someTest() { /* does make OTHER validation tests */ } 
}

现在,如果Derived的someTest()失败,则表明我的对象实际上是Base类型(myType = 1)或有缺陷的对象(myType = 0)。因为这些东西都是构造函数,因为我不能使用异常处理(嵌入式系统);我想到了这个:

{ 
  // this is the object holder test block
  // there is some latch - Base* - above = let's call it "ObjectHolder"
  extern Base* ObjectHolder;


  Derived * deriv = new Derived();
  int dType = deriv->GetMyType() ;
  if( dType == 1) // if test at base succeded but the one in derived failed
     Base = & static_cast<Base> (*deriv); // specifically slice the object
  else if(dType =2) 
     Base = deriv;
  else
     delete deriv; // this is a TYPE0 - nonworking- object so don't latch it

  // use other implemented methods to do work ...

}

现在,为什么我有这样的设计?好吧,当我设计类时,由于“Base”(类型1)和“Derived”(类型2)类的内部工作方法不同(并且有可能类型3,4,5 ....内部也不同的对象)因为我不想制作并且“if-then-else”检查每一种方法;我以为我会做出这样的设计并使不同的方法成为虚拟的,这样它们就可以被正确调用(多亏了多态),而常见的方法可以在某些Base类中。

但是现在,首先,我不确定这种奇怪的语法(&amp; static_cast&lt; Base&gt; *衍生物)是否正确(经过测试并且似乎有效)但我只是想确保这不是因为运气);其次,我不确定这是否是“建议的方法”来实现这一点 - 我有点怀疑这种语法会导致内存泄漏或其他什么......

稍微更改了代码(也修正了语法)以使问题更加清晰。

现在,因为&amp;(static_cast(* deriv))是一个错误的方法,我在想是否可以创建一个“复制构造函数”来绕过Base类的检查(这实际上是我尝试这些的原因)东西 - 我不希望在某些情况下运行测试)。如下所示:

class Base { 
    // other stuff is like above

    // cc:
    Base(const Base &other) : myType(other.myType)
    {
         // no test is performed here!
    }

    // like other one above
}

有了这篇文章,我想我现在可以在测试块上做到这一点:

{ 
   // the code above

   if( dType == 1) // if test at base succeded but the one in derived failed
     Base = new Base(*deriv); // specifically slice the object with cc

    // code goes on ... 
}

这个怎么样?

1 个答案:

答案 0 :(得分:2)

当然,如果要创建两种类型的对象,正确的方法是使用包含“if(sometest)”的工厂函数,然后创建正确的对象类型:

 Base* factory(...) 
 {
     if(sometest())
     {
         return new Derived;
     }
     else
     {
          return new Base;
     }
 }

这样,当您实际需要Base类型对象时,不会不必要地创建派生类型的对象。还要记住,如果您切割对象,则vtable 与已切片的派生对象相关联仍将是派生vtable

编辑:这里有一些代码来显示切片问题:

#include <iostream>

using namespace std;

class Base
{
public:
    virtual void func() { cout << "Base" << endl; }
};


class Derived : public Base
{
public:
    virtual void func() { cout << "Derived" << endl; }
};


int main()
{
    Base *list[10];
    for(int i = 0; i < 10; i++)
    {
        if (i % 2)
        {
            list[i] = new Base;
        }
        else
        {
            list[i] = new Derived;
        }
    }

    list[2] = &*(static_cast<Base*>(list[2]));

    for(int i = 0; i < 10; i++)
    {
        list[i]->func();
    }
    return 0;
}

输出:

Derived
Base
Derived     <- should have changed to "Base" if questio was "right".
Base
Derived
Base
Derived
Base
Derived
Base

使用原始问题中给出的“切片”语法: &(static_cast<Base>(*list[2]));(根据此处发布的代码进行了调整),在clang++g++编译器中都给出了错误。消息的本质是相同的。这是clang的变体:

error: taking the address of a temporary object of type 'Base'