我已经从我的真实代码编辑了这个,所以它更容易理解。
基类:
class MWTypes
{
public:
virtual long get() { return (0); }
};
派生类:(将会有其他类,如char,double等等。)
class TypeLong : public MWTypes
{
public:
TypeLong(long& ref) : m_long(ref) {}
~TypeLong();
long get() { return m_long; }
private:
long& m_long;
};
和存储类:
class RowSet
{
public:
void addElememnt(MWTypes elem);
MWTypes getElement();
std::vector<MWTypes> getVector() { return m_row; }
private:
std::vector<MWTypes> m_row;
};
如何调用:
for (i = 0; i < NumCols; i++) // NumCols is 3 on this instance
{
switch(CTypeArray[i]) // this is an int which identifies the type
{
case SQL_INTEGER:
{
long _long = 0;
TypeLong longObj(_long);
MWTypes *ptr = &longObj;
// some SQL code goes here that changes the value of _long,
// there is no need to include it, so this will do.
_long++;
// I now want to save the data in a vector to be returned to the user.
rowSet.addElememnt(*ptr);
///////////////////////////////////////////////
// some code happens here that is irrelevant //
///////////////////////////////////////////////
// I now want to return the typr I have saved in the vector,
// I THINK I am doing this right?
MWTypes returned = rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned.get();
///////////////////////////////////////////////
// some code happens here that is irrelevant //
///////////////////////////////////////////////
我想我在这里是正确的。 'foo'的值总是为0.我感觉这可能是我在向量中存储的方式,或者它可能是基本虚函数,因为它总是返回0。
如果我删除基类中的返回,我会收到LNK2001错误。
答案 0 :(得分:8)
MWTypes returned = rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned.get();
应该是
MWTypes* returned = &rowSet.getElement();
// lastly I want to get the value in the returned type
long foo = returned->get();
或
MWTypes& returned = rowSet.getElement(); // actually illegal, but MSVC will let you do
// lastly I want to get the value in the returned type
long foo = returned.get();
实际上,必须通过指针或引用进行多态调用。
编辑: 这不是您唯一的问题。向量存储对象(而不是指针)的事实将slice对象并销毁它们的类型信息。
有关其他信息,请参阅this faq entry,以帮助您解决问题并了解虚拟函数的调用方式。
答案 1 :(得分:3)
您正在遭受切片,因为您的收藏品存储了基本类型的副本。每当您将某些内容存储到向量中时,您的代码就会切掉基本部分并忘记其原始类型。
要解决此问题,您可以存储指向基础的指针:std::vector<MWTypes*>
,但是您必须正确管理实例以避免内存泄漏。
class RowSet
{
public:
// addElement assumes responsibility for the memory allocated for each 'elem'
void addElement(MWTypes* elem);
MWTypes* getElement();
std::vector<MWTypes*> getVector() { return m_row; }
// Destructor calls delete on every pointer in m_row
~RowSet();
private:
std::vector<MWTypes*> m_row;
};
然后你需要修改你的代码,调用addElement()来创建new
个实例,并重新获得回报:
rowSet.getElement()->get();
答案 2 :(得分:3)
根本问题在于您正在对MWTypes类型的对象进行复制,从而丢失其特定的子类。如果要使用基类的未知子类的对象,则只能使用指向基类型的指针或引用,而不能使用它的实际实例。
不提供函数“get”的实现,因为ascanio的代码显示(使函数“纯虚拟”)将阻止您能够犯这种复制错误,因为编译器不允许您实例化类MWTypes你做到了(它会说这个类是“抽象的”)。
答案 3 :(得分:1)
这个函数void addElememnt(MWTypes elem);
存在问题。它应该是void addElememnt(MWTypes* elem);
或void addElememnt(MWTypes& elem);
。这是因为通过让一个参数按值传递,它会丢失它的多态性。传递by-value调用基类的复制构造函数,并且只复制基类(和vtable)的内容,忽略派生类中的其余内容。
此外,如果需要存储某个基类类型的值,则需要考虑使用基类类型的指针列表。
答案 4 :(得分:0)
问题在于:
class RowSet
{
public:
void addElememnt(MWTypes elem);
您按值elem
,而不是按指针或引用,因此TypeLong
子对象被切掉,在这里:(参考:What Is The Slicing Problem in C++?)
TypeLong longObj(_long);
MWTypes *ptr = &longObj;
_long++;
rowSet.addElememnt(*ptr);
您需要更改addElement
以获取引用或指针。
答案 5 :(得分:0)
您的vector
,getElement
和addElememnt
部分都会调用对象切片,因为它们按值存储基础对象。您需要使用指针或引用才能使用运行时多态性。
在这种情况下,boost::ptr_vector
或vector
的{{1}}可能是你想要的。