<三>关于重载 隐藏 覆盖
重载关系
一组函数要重载,必须处在同一个作用域中 ,而且函数名字相同,参数列表不同
代码1中的Base中的 show() 和show(int) 属于重载
代码2中的Base中的 show() 和Derive中的show()不属于重载不在同一个作用域下面
隐藏/重定义的关系(主要是指作用域隐藏)
在继承结构当中,当子类和父类中有同名成员时,子类成员会隐藏父类成员.子类成员和父类成员构成隐藏关系,也叫重定义。
只要函数名相同,就构成隐藏关系。想要调用父类的成员就要指定作用域,显式的调用。
子类把基类的同名成员全部都给隐藏掉了,只要名字相同就会发生隐藏,无所谓子类函数的返回值,参数列表是否与父类一致.
例如代码2中的 Derive中的show() 和Base()中的show() ,show(int) 是隐藏关系
隐藏发生的主要原因,就是当子类有父类的同名成员时,子类对象访问该成员时,会发生冲突。所以编译器的处理方式是,优先考虑子类域中的自身成员。
即,子类对象访问某成员时,如ch.m_m 或者ch.f(),成员变量和成员函数都一样。编译器首先在子类域中检索,如果在子类域中找到该成员,则检索结束,返回该成员进行访问。
如果在子类域中找不到该成员,则去父类域中检索。如果父类域中存在,则返回该成员进行访问,如果父类域中也不存在,则编译错误,该成员无效。
当父子类域都存在同一成员时,编译器优先在子类中检索,就算父类域中也存在该同名成员,也不会被检索到。
因此,父类域中的该成员被子类域中的该同名成员隐藏,即访问时完全以为该成员不存在,如果想访问父类域中的该成员,只能通过显示调用的方式,即:ch.Father::m_m;
代码1
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base"<<endl;
}
void show(){cout<<"Base Show()"<<endl;}
void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive"<<endl;
}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main(){
Derive d(20);
d.show(); //正常调用基类show()
d.show(100); //正常调用基类show(int)
return 0;
}
代码2
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base"<<endl;
}
void show(){cout<<"Base Show()"<<endl;}
void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive"<<endl;
}
void show(){cout<<"Derive Show()"<<endl;}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main(){
Derive d(20);
d.show(); //调用子类show()
d.show(100);//调用报错 报错信息 "Derive::show()函数不接受1个参数"
// 即 Derive中的show()方法把Base中的show()和show(int)都给隐藏掉了
// 所以d.show()没问题,调用的是派生类的show(),但是d.show(100)报错了,因为
// 父类的show()和show(int)都被隐藏了,而派生类Derive中没有 show(int)方法所以报错了
// 如果想调用父类的show(int) 要这样写 d.Base.show(100);
return 0;
}
基类对象 -> 派生类对象 类型由上向下转 NOT OK
Base b(10);
Derive d(20);
d=b;// NOT OK
派生类对象 ->基类对象 类型由下向上转 OK
Base b(10);
Derive d(20);
b=d;//OK
派生类指针(引用) ->基类指针 类型由下向上转 OK
Base b(10);
Derive d(20);
Base *pb =&d;// OK 如下图, 基类指针只能访问到基类那一部分的成员,所以是安全的
代码3
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base"<<endl;
}
void show(){cout<<"Base Show()"<<endl;}
void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive"<<endl;
}
void show(){cout<<"Derive Show()"<<endl;}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main(){
Base b(10);
Derive d(20);
Base *pb =&d;
pb->show(); //调用的是基类的 show
pb->show(100);//调用的是基类的 show(int)
((Derive *)pb)->show(); //强转后 调用的是派生类的 show
}
基类指针(引用) -> 派生类对象 类型由上向下转 NOT OK
Base b(10);
Derive d(20);
Derive *pb =&b;// NOT OK pb指针能够访问的区域超过了实际对象b的内存块 ,危险访问
代码4
#include <iostream>
using namespace std;
class Base{
public:
Base(){
cout<<"Base()"<<endl;
}
void show(){
cout<<"Base show()"<<endl;
}
void show(int x){
cout<<"Base show(int x)"<<endl;
}
~Base(){
cout<<"~Base()"<<endl;
}
private:
int ma;
};
class Derive :public Base{
public:
Derive(){
cout<<"Derive()"<<endl;
}
void show(){
cout<<"Derive show()"<<endl;
}
~Derive(){
cout<<"~Derive()"<<endl;
}
private:
int ma;
};
int main(){
Derive d;
Derive *pd=&d;
d.show();
d.show(100); //编译报错, Derive 的void show()方法把Base 的void show() void show(int x) 都隐藏了
pd->show(100);//编译报错 Derive 的void show()方法把Base 的void show() void show(int x) 都隐藏了
return 0;
}
代码5
#include <iostream>
using namespace std;
class Base{
public:
Base(){
cout<<"Base()"<<endl;
}
virtual void show(){
cout<<"Base show()"<<endl;
}
void show(int x){
cout<<"Base show(int x)"<<endl;
}
~Base(){
cout<<"~Base()"<<endl;
}
private:
int ma;
};
class Derive :public Base{
public:
Derive(){
cout<<"Derive()"<<endl;
}
virtual void show(){
cout<<"Derive show()"<<endl;
}
~Derive(){
cout<<"~Derive()"<<endl;
}
private:
int ma;
};
int main(){
Derive *pd=new Derive();
pd->show(100); //编译报错,Derive 中的show() 函数,只要名字与Base中有相同名字的函数的,就会隐藏掉Base中所有的show方法(不管加不加virtual),包括void show() void show(int x)
return 0;
}