我的虚拟函数无法C++工作

My virtual function wont work C++

本文关键字:C++ 工作 虚拟 函数 我的      更新时间:2023-10-16

我已经从我的真实代码中编辑了它,以便更容易理解。

基类:

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。我有一种感觉,这可能是 Im 存储在向量中的方式,也可能是基本的虚函数,因为它总是返回 0。

如果我删除基类中的返回,我会收到LNK2001错误。

 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 类型的对象,从而丢失它们特定的子类。如果要使用基类的未知子类的对象,则只能使用指向基类型的指针或引用,而不能使用基类型的实际实例。

没有像 ascanio 的代码所示提供函数"get"的实现(使函数"纯虚拟")将阻止您犯此复制错误,因为如果您这样做,编译器不会让您实例化类 MWTypes(它会说该类是"抽象的")。

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

要解决此问题,您可以存储指向 base: 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();

你的问题在于这个函数void addElememnt(MWTypes elem);。它应该是 void addElememnt(MWTypes* elem);void addElememnt(MWTypes& elem); .这是因为通过按值传递参数,它失去了它的多态性。传递 by-value 调用基类的复制构造函数,并且只复制基类(和 vtable)的内容,而忽略派生类中的其余内容。

此外,如果需要存储某个基类类型的值,则需要考虑使用基类类型的指针列表。

问题出在这里:

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

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

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

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

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

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