hg_git hg_git - 4 months ago 14
C++ Question

do I need a virtual function

I've a base class as follows -

Class Base {

int a;
int b;
someInfo c;

void setInfo(someInfo);
someInfo getInfo();

defined as -

struct someInfo{
std::string name;
std::string school;

Now I've a child class as follows:

Class child: public Base{

int e;
int f;
someMoreInfo g;

void setInfo(someMoreInfo);
someMoreInfo getInfo();

struct as -

struct someMoreInfo{
someInfo i;
int j;

Now when implementing
of the child class, do I need to make the base class's respective function
and override them here? Because everyone is saying so and I have got no idea why should I do that and why this wouldn't work already, since both are different set of functions, difference being in return value or that of parameter.

Any help for this fellow confused student would be appreciated :)


It appears that what you want is for your Derived class to support the following interface:

someInfo si;
someMoreInfo smi;
Base* pB = new Derived;

// Setting info
pB->setInfo(si);       // Set the `Base::c` member of `*pB`
pB->setInfo(smi);      // Set the `Derived::g` member of `*pB`

// Getting info
someInfo pB_si = pB->getInfo();   // Get  `Base::c` from `*pB`
someMoreInfo pB_smi = pB->getInfo();   // Get  `Derived::g` from `*pB`

Setting info: overloading

You're actually correct that you don't need setInfo to be virtual, because Derived::setInfo doesn't replace the Base method; both are supposed to be accessible.

Unfortunately, as I've noted in a comment, by default Base::setInfo gets hidden by Derived::setInfo, regardless of the signature (!). Yes, this is surprising behavior; Scott Meyers notes in Effective C++ that this "surprises every C++ programmer the first time they encounter it" (Item 33 of the third edition).

Fortunately, the solution is simple. You need the using keyword:

Class child: public Base{

  // ... private members...

    using Base::setInfo;
    void setInfo(someMoreInfo);

  // .. rest of class...

This exposes the otherwise hidden name Base::setInfo, permitting overload resolution to happen as if both versions of setInfo were defined inside Derived.

Getting info: return-dependent overload resolution

C++ does not support overloading on return types. You can easily check this:

class Foo
    int foo() { return 3; }
    double foo() { return 83.4; }

Clang gives the following error (which is much more helpful than the GCC error):

error: functions that differ only in their return type cannot be overloaded

Now, you might ask, "why not?" Indeed, I know of at least one language, Perl, that supports different behavior based on the "context" in which an expression is evaluated.

This is actually pretty confusing (at least for those who aren't fans of Perl, I guess). In general, programmers don't expect different functions to be called depending on the context in which the function is called. And there are many contexts that don't clearly indicate the expected return type:

std::cout << Foo().foo() << std::endl;  // AMBIGUOUS!

... so there is simply no solution: you cannot differentiate two functions merely in their return type. You must provide different names for the two functions.