Effective C++ 笔记 —— Item 33: Avoid hiding inherited names.

C++'s name-hiding rules do just that: hide names. Whether the names correspond to the same or different types is immaterial. 

int x; // global variable
void someFunc()
{
    double x; // local variable
    std::cin >> x; // read a new value for local x
}

We know that when we’re inside a derived class member function and we refer to something in a base class (e.g., a member function, a typedef, or a data member), compilers can find what we’re referring to because derived classes inherit the things declared in base classes. The way that actually works is that the scope of a derived class is nested inside its base class's scope. For example:

class Base
{
private:
    int x;
public:
    virtual void mf1() = 0;
    virtual void mf2();
    void mf3();
    // ...
};

class Derived: public Base 
{
public:
    virtual void mf1();
    void mf4();
    // ...
};

The only thing that matters in this discussion is that they’re names. What they're names of is irrelevant.

Consider the previous example again, except this time let’s overload mf1 and mf3, and let's add a version of mf3 to Derived. (As Item 36 explains, Derived's declaration of mf3 — an inherited non-virtual function.)

class Base 
{
private:
    int x;
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
    virtual void mf2();
    void mf3();
    void mf3(double);
    // ...
};
class Derived: public Base 
{
public:
    virtual void mf1();
    void mf3();
    void mf4();
    // ...
};

The scope-based name hiding rule hasn't changed, so all functions named mf1 and mf3 in the base class are hidden by the functions named mf1 and mf3 in the derived class. From the perspective of name lookup, Base::mf1 and Base::mf3 are no longer inherited by Derived!

Derived d;
int x;
// ...
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Derived::mf1 hides Base::mf1

d.mf2(); // fine, calls Base::mf2
d.mf3(); // fine, calls Derived::mf3
d.mf3(x); // error! Derived::mf3 hides Base::mf3

As you can see, this applies even though the functions in the base and derived classes take different parameter types, and it also applies regardless of whether the functions are virtual or non-virtual. 

Unfortunately, you typically want to inherit the overloads.You do it with using declarations:

class Base 
{
private:
    int x;
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
    virtual void mf2();
    void mf3();
    void mf3(double);
    // ...
};

class Derived: public Base 
{
public:
    using Base::mf1; // make all things in Base named mf1 and mf3
    using Base::mf3; // visible (and public) in Derived’s scope
    virtual void mf1();
    void mf3();
    void mf4();
    // ...
};

Now inheritance will work as expected:

Derived d;
int x;
// ...
d.mf1(); // still fine, still calls Derived::mf1
d.mf1(x); // now okay, calls Base::mf1
d.mf2(); // still fine, still calls Base::mf2
d.mf3(); // fine, calls Derived::mf3
d.mf3(x); // now okay, calls Base::mf3 (The int x is implicitly converted to a double so that the call to Base::mf3 is valid.)

This means that if you inherit from a base class with overloaded functions and you want to redefine or override only some of them, you need to include a using declaration for each name you’d otherwise be hiding. If you don't, some of the names you’d like to inherit will be hidden.

It's conceivable that you sometimes won't want to inherit all the functions from your base classes.For example, suppose Derived privately inherits from Base, and the only version of mf1 that Derived wants to inherit is the one taking no parameters. A using declaration won't do the trick here, because a using declaration makes all inherited functions with a given name visible in the derived class. No, this is a case for a different technique, namely, a simple forwarding function:

class Base 
{
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
    // ... // as before
};

class Derived: private Base {
public:
    virtual void mf1() // forwarding function; implicitly inline — see Item 30. (For info on calling a pure virtual function, see Item 34.)
    { 
        Base::mf1();
    } 
}; 

// ...

Derived d;
int x;
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Base::mf1() is hidden

Things to Remember:

  • Names in derived classes hide names in base classes. Under public inheritance, this is never desirable.
  • To make hidden names visible again, employ using declarations or forwarding functions.
原文地址:https://www.cnblogs.com/zoneofmine/p/15266459.html