The hiding rule in C++

是什么

更里层的scope里的变量名会使外层的同名变量被隐藏,即使该名字是一个签名不一样的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <typeinfo>
using namespace std;

namespace A {
char x;
};

namespace B {
using namespace A;
int x;
};

int main() {
cout << typeid(B::x).name() << endl;
}

将会输出:

1
int

问题

如果在继承类里定义一个函数f, 则基类里的所有名为f的函数都将被隐藏,即使返回类型和参数不一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
struct A {
void f() { }
};

struct B : A {
void f(int) { }
};

int main() {
B obj_B;
obj_B.f(3);
// obj_B.f(); // 编译报错 f()未定义
}

我们可以用using声明使基类的所有f可见。继承类里的重定义会覆盖基类的定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

struct A {
void f() { cout << "void A::f()" << endl; }
void f(int) { cout << "void A::f(int)" << endl; }
};

struct B : A {
using A::f;
void f(int) { cout << "void B::f(int)" << endl; }
};

int main() {
B obj_B;
obj_B.f(3);
obj_B.f();
}

将会输出:

1
2
void B::f(int)
void A::f()

Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals

将本需使用public重载虚函数来定义的一组函数,通过public重载非虚函数和protected不重载虚函数这种方式来定义。如:

1
2
3
4
5
class Base {
public:
virtual void f(int x);
virtual void f(double x);
};

可定义为:

1
2
3
4
5
6
7
8
class Base {
public:
void f(int x) { f_int(x); } // Non-virtual
void f(double x) { f_dbl(x); } // Non-virtual
protected:
virtual void f_int(int);
virtual void f_dbl(double);
};

这种方式下,隐藏规则导致的风险在基类处理掉了。

参考

Name hiding - IBM Knowledge Center

Overloading member functions from base and derived classes - IBM Knowledge Center

Should I use protected virtuals instead of public virtuals? - isocpp