我的虚拟函数无法使用 C++
我从我的真实代码中编辑了这个,这样更容易理解。
基类:
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 错误。
I have edited this from my real code, so that it is a little easier to understand.
The base class:
class MWTypes
{
public:
virtual long get() { return (0); }
};
The derived class: (There are going to be other classes like char, double etc etc . . .)
class TypeLong : public MWTypes
{
public:
TypeLong(long& ref) : m_long(ref) {}
~TypeLong();
long get() { return m_long; }
private:
long& m_long;
};
and the storage class:
class RowSet
{
public:
void addElememnt(MWTypes elem);
MWTypes getElement();
std::vector<MWTypes> getVector() { return m_row; }
private:
std::vector<MWTypes> m_row;
};
How it is called:
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 //
///////////////////////////////////////////////
I think I am on the right lines here. The value of 'foo' is always 0. I have a feeling this could be the way Im storing in the vector, or it could be the base virtual function, as it always returns 0.
If I remove the return in my base class I get LNK2001 errors.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
应该是
或者
事实上,多态调用必须通过指针或引用进行。
编辑:这不是您唯一的问题。事实上,向量存储对象(而不是指针)将切片对象并销毁它们类型信息。
请参阅此常见问题解答条目了解更多信息帮助您解决问题并了解如何调用虚函数。
should be
or
Indeed, polymorphic calls must be made via a pointer or a reference.
EDIT: this is not your only problem. The fact that the vector stores objects (and not pointers) will slice the objects and destroy their type information.
See this faq entry for additional info to help you solve your problem and understand how virtual functions are called.
根本问题是您正在制作 MWTypes 类型的对象的副本,从而丢失了它们的特定子类。如果你想使用基类的未知子类的对象,那么你只能使用基类型的指针或引用,而不是它的实际实例。
不提供函数“get”的实现(如 ascanio 的代码所示)(使函数成为“纯虚拟”)将阻止您犯此复制错误,因为如果您这样做,编译器将不会让您实例化类 MWTypes (它会说该类是“抽象的”)。
The fundamental problem is that you are making copies of your objects of type MWTypes, thus losing their particular subclass. If you want to use an object of an unknown subclass of the base class, then you can only use a pointer or reference to the base type, not an actual instance of it.
Not providing an implementation of the function "get" as ascanio's code shows (making the function "pure virtual") would prevent you from being able to make this copying mistake, because the compiler would not let you instantiate the class MWTypes if you did that (it would say the class is "abstract").
由于您的集合存储了基本类型的副本,因此您正遭受切片之苦。每当您将某些内容存储到向量中时,您的代码都会切掉基本部分,并且会忘记其原始类型。
要解决此问题,您可以存储指向基址的指针:
std::vector
,但是您必须正确管理实例以避免内存泄漏。然后,您需要修复调用 addElement() 的代码以创建
new
实例,并再次获取 long:You are suffering from slicing since your collection stores copies of the base type. Whenever you store something into the vector, your code just slices off the base part and it forgets its original type.
To fix this, you could store pointers to the base:
std::vector<MWTypes*>
, but then you have to manage your instances correctly to avoid memory leaks.Then you need to fix your code which calls addElement() to create
new
instances, and to get the long back again:你的问题出在这个函数
void addElememnt(MWTypes elem);
。它应该是void addElememnt(MWTypes* elem);
或void addElememnt(MWTypes& elem);
。这是因为通过按值传递参数,它就失去了多态性。按值传递调用基类的复制构造函数,并且仅复制基类(和 vtable)的内容,忽略派生类的其余内容。另外,如果需要存储某个基类类型的值,则需要考虑使用该基类类型的指针列表。
You're problem lies with this function
void addElememnt(MWTypes elem);
. It should be eithervoid addElememnt(MWTypes* elem);
orvoid addElememnt(MWTypes& elem);
. This is because by having an argument to be passed by-value, it loses it's polymorphism. The passing by-value calls the copy constructor of the base class and ONLY copies the contents of the base class (and the vtable) ignoring the rest from the derived class.Also, if you need to store values of a certain base-class type, you need to consider using a list of pointers of the base-class type.
问题在于:
您通过值而不是指针或引用获取
elem
,因此TypeLong
子对象被切掉,这里:(参考:C++ 中的切片问题是什么?)您需要更改
addElement
以获取引用或指针。The problem lies here:
You are taking
elem
by value, not by pointer or by reference, so theTypeLong
subobject is sliced away, here: (reference: What Is The Slicing Problem in C++?)You need to change
addElement
to take a reference or a pointer.您的
vector
、getElement
和addElememnt
部分都调用对象切片,因为它们按值存储基础对象。您需要使用指针或引用才能使用运行时多态性。在这种情况下,您可能需要的是
boost::ptr_vector
或shared_ptr
的vector
。Your
vector
,getElement
, andaddElememnt
parts all invoke object slicing since they store the base object by value. You need to work with pointers or references in order to use runtime polymorphism.In this case either a
boost::ptr_vector
or avector
ofshared_ptr
is probably what you want.