views:

192

answers:

4

a more exact version of the code is:

class SomeParam;
class IBase
{
public:
    virtual void Func(SomeParam* param = NULL)
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);

This gives me:
"Base func"
"Base func"

+1  A: 

I've tried a copy of the code you posted on VS2008 and it works fine.

I can only suggest that your actual code is more like:

void FuncCaller(IBase instance)
{
    instance.Func();
}

void Funcs()
{
DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(*a);
FuncCaller(*b);
}

where FuncCaller slices the base part off the derived instances.

quamrana
+2  A: 

It looks like you have provided a simplified version of your code to make it more readable, but you have oversimplified inadvertently.

The most likely reasons for your behaviour are:

  • Slicing in FuncCaller() (see quamrana's answer for the details)
  • Wrong overriding, such as making the derived class function const, while the base class function is not const

EDIT: After reading the edited question, it is clearly the second reason. You are not overriding the base class function, but hiding it in the derived classes with a new definition. You need to keep exactly the same signature (covariance does not apply here, since the function returns void) in the derived classes. In code, you need to do either:

class SomeParam;
class IBase
{
public:
    virtual void Func(SomeParam* param = NULL)
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func(SomeParam* param = NULL)
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func(SomeParam* param = NULL)
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);

or

class SomeParam;
class IBase
{
public:
    virtual void Func()
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);
Gorpik
As AndreyT says, defining the default value for the parameters is not strictly necessary; but not defining the same default value in all overrides of the same function would be very bad practice.
Gorpik
A: 

I found the reason:
The overriden virtual functions also must have a default parameter like Base's.like:

class DerivedB : public IBase
{
public:
    void Func(SomeParam* param=NULL)
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

Thanks for the answers guys.

Taz
They don't have to define a *default* argument specifically. What they do need though is a parameter, so that the base `Func` signature matches the derived `Func` signature. Whether the derived version has a default argument doesn't matter at all.
AndreyT
@AndreyT: True, but not defining the same default value for all parameters would be awful practice.
Gorpik
A: 

Your virtual function is not overridden.

Your supposedly "virtual" methods in the derived classes have different signatures. The method in the base class has one parameter, while the methods in the derived classes have no parameters. Because of this, the methods in the derived classes are completely unrelated to the base class method. They don't override the base class method. This is why the base class method is always called.

AndreyT