我为我公司建立的项目有一些类结构。在某些时候,我已经看到派生对象的“通常不需要的”切片实际上可以使我的代码有效。请注意:
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 ...
}
这个怎么样?
答案 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'