0

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

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() 失败,这表明我的对象实际上是基本类型 (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 ...

}

现在,我为什么会有这样的设计?好吧,在我设计类时,由于“基础”(类型 1)和“派生”(类型 2)类的内部工作方法不同(并且有可能是 3、4、5 类型......内部也不同的对象)并且因为我不想在每个方法中都进行“if-then-else”检查;我想我会做出这样的设计并使不同的方法虚拟化,以便可以正确调用它们(感谢多态性),而常用方法可以在某个基类中。

但是现在,首先,我不确定那个奇怪的语法( & static_cast < Base > *deriv )是否正确(经过测试,似乎可以工作,但我只是想确保这不是因为运气);其次,我不确定这是否是实现这一目标的“建议方法” - 我有点怀疑这种语法会导致内存泄漏或其他什么......

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

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

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 ... 
}

那这个呢?

4

1 回答 1

2

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

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

这样,当您实际需要 Base 类型对象时,就不会不必要地创建对象的派生类型。还要记住,如果您对对象vtable 进行切片,则与已切片的 Derived 对象关联仍然是 Derived 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'
于 2013-01-25T20:36:46.720 回答