user713885
user713885

Reputation: 11

Virtual Function

I have a question regarding to the C++ virtual function.

The derived class (DerivedAlgo) implements the virtual function (BaseAlgo::process) but changes a little bit in the function signature by using the DerivedData type as the input parameter instead of BaseData.

Despite the pure abstract function in the base class, I am still able to create an instance of the DerivedAlgo class and the compiler does not complain at all.

I just wonder anyone knows any C++ rule which can explain the following code.

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
    std::cout << "hello world!" << std::endl;
  }
};

In my another sample code, I define process(DerivedData&) and process(BaseData&).

The compiler can still run through without complaining any ambiguity.

class DerivedAlgo{
public:
  virtual void process(DerivedData& data){...}
  virtual void process(BaseData& data){...}
};
BaseData baseData;
DerivedData derivedData;
derivedAlgo.process(baseData);
derivedAlgo.process(derivedData);

I really appreciate any of your inputs. Thanks!

Upvotes: 1

Views: 635

Answers (3)

lurscher
lurscher

Reputation: 26943

the problem you have is that c++ does not support double dispatch. You need to use a Visitor pattern on your BaseAlgo class.

Upvotes: 0

John Dibling
John Dibling

Reputation: 101446

Are you sure you're not getting a compiler error?

When I compile this (in MSVC9):

#include <cstdlib>
#include <memory>
#include <iostream>

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
      data;
    std::cout << "hello world!" << std::endl;
  }
};

int main()
{
    DerivedAlgo da;
}

I get the expected error:

1>.\main.cpp(21) : error C2259: 'DerivedAlgo' : cannot instantiate abstract class
1>        due to following members:
1>        'void BaseAlgo::process(BaseData &)' : is abstract
1>        .\main.cpp(9) : see declaration of 'BaseAlgo::process'

This is because you cannot override virtuals with different parameter lists:

10.3 Virtual Functions

2/ If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides97) Base::vf.

The only leeway you have in declaring overrides in the derived class is with covariant return types.

It's possible your compiler didn't thoroughly check your code if you never actually call the derived class.

Upvotes: 1

Mark B
Mark B

Reputation: 96233

Your first example doesn't compile on g++ 4.2. For reference I did this:

#include <iostream>

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
    std::cout << "hello world!" << std::endl;
  }
};

int main()
{
    DerivedAlgo da;

    return 0;
}

And got this:

error: cannot declare variable 'da' to be of abstract type 'DerivedAlgo'
note:   because the following virtual functions are pure within 'DerivedAlgo'
note:  virtual void BaseAlgo::process(BaseData&)

If something like my example did compile then you almost surely have a buggy compiler.

Your second example will compile because it overrides the abstract function. The first call will call the base data version while the second call will call the derived version of process.

Note that in your first example you're hiding the process(base) version of the function, not overriding it at all. You shouldn't change the function signature when overriding virtual functions.

Upvotes: 1

Related Questions