我的虚拟函数无法使用 C++

发布于 2024-11-06 16:37:59 字数 1812 浏览 3 评论 0原文

我从我的真实代码中编辑了这个,这样更容易理解。

基类:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

请持续率性 2024-11-13 16:37:59
 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();

事实上,多态调用必须通过指针或引用进行。

编辑:这不是您唯一的问题。事实上,向量存储对象(而不是指针)将切片对象并销毁它们类型信息。

请参阅此常见问题解答条目了解更多信息帮助您解决问题并了解如何调用虚函数。

 MWTypes returned = rowSet.getElement();

 // lastly I want to get the value in the returned type
 long foo = returned.get();

should be

 MWTypes* returned = &rowSet.getElement();

 // lastly I want to get the value in the returned type
 long foo = returned->get();

or

 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();

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.

薄荷→糖丶微凉 2024-11-13 16:37:59

根本问题是您正在制作 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").

独夜无伴 2024-11-13 16:37:59

由于您的集合存储了基本类型的副本,因此您正遭受切片之苦。每当您将某些内容存储到向量中时,您的代码都会切掉基本部分,并且会忘记其原始类型。

要解决此问题,您可以存储指向基址的指针:std::vector,但是您必须正确管理实例以避免内存泄漏。

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 实例,并再次获取 long:

rowSet.getElement()->get();

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.

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

Then you need to fix your code which calls addElement() to create new instances, and to get the long back again:

rowSet.getElement()->get();
疯狂的代价 2024-11-13 16:37:59

你的问题出在这个函数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 either void addElememnt(MWTypes* elem); or void 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.

铃予 2024-11-13 16:37:59

问题在于:

class RowSet
{
public:
    void addElememnt(MWTypes elem);

您通过值而不是指针或引用获取elem,因此TypeLong子对象被切掉,这里:(参考:C++ 中的切片问题是什么?

TypeLong longObj(_long);
MWTypes *ptr = &longObj;
_long++;
rowSet.addElememnt(*ptr);   

您需要更改 addElement 以获取引用或指针。

The problem lies here:

class RowSet
{
public:
    void addElememnt(MWTypes elem);

You are taking elem by value, not by pointer or by reference, so the TypeLong subobject is sliced away, here: (reference: What Is The Slicing Problem in C++?)

TypeLong longObj(_long);
MWTypes *ptr = &longObj;
_long++;
rowSet.addElememnt(*ptr);   

You need to change addElement to take a reference or a pointer.

兔姬 2024-11-13 16:37:59

您的 vectorgetElementaddElememnt 部分都调用对象切片,因为它们按值存储基础对象。您需要使用指针或引用才能使用运行时多态性。

在这种情况下,您可能需要的是 boost::ptr_vectorshared_ptrvector

Your vector, getElement, and addElememnt 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 a vector of shared_ptr is probably what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文