我的虚函数不适用于C ++

时间:2011-05-13 15:12:46

标签: c++ inheritance vector polymorphism virtual

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

基类:

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错误。

6 个答案:

答案 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)

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

在这种情况下,boost::ptr_vectorvector的{​​{1}}可能是你想要的。