【C++grammar】名字隐藏与重定义
1、继承中的名字隐藏
1.基类同名函数被隐藏的现象描述
在学习变量作用域的时候知道,全局变量可能被函数里面的同名局部变量所隐藏,如果要在函数里面使用这个同名全局变量,那么就要使用域解析运算符。
在继承中也会出现上述类似的情况,下面是名字隐藏的形式:
基类和派生类中都有一个同名函数,不同的是派生类的函数有个整型形参。
在主函数中调用f(),那么调用的到底是基类的函数还是派生类的函数?
class P{
public:
void f(){}
};
class C :public P{
public:
void f(int x){}
};
int main()
{
C c;
c.f();
}
编译器会报错。
2.问题理解
我们可以将派生类看做是内部作用域,基类看做是外部作用域。内部作用域的函数f()将外部作用域的f()给隐藏掉了。
那么在C类中就看不到基类中的f()同名函数了。
这个做法可以帮助程序员避免写出带有危险性的代码。
3.避免现象
那么如何解决这个问题呢?
using 声明语句可以将基类成员引入到派生类定义中,显式声明。
class P{
public:
void f(){}
};
class C :public P{
public:
using P::f;
void f(int x){}
};
int main()
{
C c;
c.f();
}
其实还有两种写法:
1、
class P{
public:
void f(){}
};
class C :public P{
public:
void f(int x){}
};
int main()
{
C c;
c.P::f();
}
2、
class P{
public:
void f(){}
};
class C :public P{
public:
void f(int x){}
};
int main()
{
C c;
static_cast<P>(c).f();
}
2、重定义
1.现象描述
名字隐藏在重定义函数的时候有比较大的作用。因为有名字隐藏,所以我们可以在子类里面重新定义一个与基类里面名字参数一样的函数
。
之前定义了基类shape:
其中,toString函数用来描述对象的信息。基类可以调用这个函数,但是基类是无法输出派生类信息的。
例如形状就不能输出它的派生类:圆,的半径。只能输出颜色和是否填充。
我们可以在派生类里面重新定义toString函数用来描述派生类对象,这样就不会调用基类的toString函数了。
2.重定义与重载的区别
重载
多个函数名字相同,但至少以下一个特征不同:
1、参数类型(parameter type)
2、参数数量(parameter number)
3、参数顺序(parameter sequence)
重定义
1、函数特征相同:同名、同参数、返回值类型
2、在基类和派生类中都有定义
3.能否使用 using 将基类成员引入到派生类定义中
派生类B中的 foo()函数是对基类A中的 foo() 函数的重定义。
那么在类B中,能否使用 using 讲基类A中的foo()函数引入到派生类B中?为什么?
#include<iostream>
#include<string>
using namespace std;
class A {
public:
string func() { return "aaa"; }
};
class B :public A {
public:
using A::func;
string func() { return "bbb"; }
};
int main() {
A a;
B b;
cout<<a.func()<<endl;
cout<<b.func()<<endl;
}
结果是:
aaa
bbb
编译运行正常通过,所以还是调用了 子类 的函数。