开发者

My virtual function wont work C++

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_INTE开发者_开发百科GER:
    {
    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.


 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.


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").


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


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜