0

I made a class with virtual function f() then in the derived class I rewrote it like the following f(int) why can't I access the base class function throw the child instance ?

class B{
public:
    B(){cout<<"B const, ";}
    virtual void vf2(){cout<<"b.Vf2, ";}


};
class C:public B{
public:
    C(){cout<<"C const, ";}
    void vf2(int){cout<<"c.Vf2, ";}
};

int main()
{
    C c;
    c.vf2();//error should be vf2(2)

}
Khaledvic
  • 534
  • 4
  • 16

4 Answers4

4

You have to do using B::vf2 so that the function is considered during name lookup. Otherwise as soon as the compiler finds a function name that matches while traversing the inheritance tree from child -> parent -> grand parent etc etc., the traversal stops.

class C:public B{
public:
    using B::vf2;
    C(){cout<<"C const, ";}
    void vf2(int){cout<<"c.Vf2, ";}
};

You are encountering name hiding. Here is an explanation of why it happens ?

Community
  • 1
  • 1
parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
1

In C++, a derived class hides any base class member of the same name. You can still access the base class member by explicitly qualifying it though:

int main()
{
    C c;
    c.B::vf2();

}
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
0

You were caught by name hiding.

Name hiding creeps up everywhere in C++:

int a = 0

int main(int argc, char* argv[]) {
  std::string a;
  for (int i = 0; i != argc; ++i) {
    a += argc[i];                    // okay, refers to std::string a; not int a;
    a += " ";
  }
}

And it also appears with Base and Derived classes.

The idea behind name hiding is robustness in the face of changes. If this didn't exist, in this particular case, then consider what would happen to:

class Base {
};

class Derived: public Base {
public:
  void foo(int i) {
    std::cout << i << "\n";
  }
};

int main() {
  Derived d;
  d.foo(1.0);
}

If I were to add a foo overload to Base that were a better match (ie, taking a double directly):

void Base::foo(double i) {
  sleep(i);
}

Now, instead of printing 1, this program would sleep for 1 second!

This would be crazy right ? It would mean that anytime you wish to extend a base class, you need to look at all the derived classes and make sure you don't accidentally steal some method calls from them!!

To be able to extend a base class without ruining the derived classes, name hiding comes into play.

The using directive allows you to import the methods you truly need in your derived class and the rest are safely ignored. This is a white-listing approach.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
0

When you overload a member function in a base class with a version in the derived class the base class function is hidden. That is, you need to either explicitly qualify calls to the base class function or you need a using declaration to make the base class function visible via objects of the derived class:

struct base {
    void foo();
    void bar();
};
struct derived: base {
    void foo(int);
    using base::foo;
    void bar(int);
};
int main() {
    derived().foo();       // OK: using declaration was used
    derived().bar();       // ERROR: the base class version is hidden
    derived().base::bar(); // OK: ... but can be accessed if explicitly requested
}

The reason this is done is that it was considered confusing and/or dangerous when a member function is declared by a derived function but a potenially better match is selected from a base class (obviously, this only really applies to member functions with the same number of arguments). There is also a pitfall when the base class used to not have a certain member function: you don't want you program to suddenly call a different member function just because a member function is being added to the base class.

The main annoyance with hiding member functions from bases is when there is a set of public virtual functions and you only want to override one of them in a derived class. Although just adding the override doesn't change the interface using a pointer or a reference to the base class, the derived class can possibly not used in a natural way. The conventional work-around for this to have public, non-virtual overload which dispatch to protected virtual functions. The virtual member function in the various facets in the C++ standard library are an example of this technique.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380