一、同名成员
为了在派生类中使用基类的同名成员,必须在该成员名之前加上基类名和作用域标识符 “ :: ”,格式为:基类名::成员名
派生类可以重新说明与基类成员同名的成员,如果在派生类中定义了与基类成员同名的成员,则称派生类成员覆盖了基类的同名成员。
在面向对象程序设计中,若要在派生类中对基类继承过来的某些函数功能进行扩充和改造,都可以通过这样的覆盖来实现。这种覆盖的方法,是对基类成员改造的关键手段,是程序设计中经常使用的方法。
例 1: 同名成员举例(程序片段)
#include<iostream>
using namespace std;
class X{
public:
int f();
};
class Y:public X{
public:
int f();
int g();
};
void Y::g(){
f(); //访问派生类中的 f(),即被调用的函数是 Y::f(),若要访问基类中的 f(),应改写成 X::f()
}
对于派生类的对象的访问,也有相同的结论,例如,
Y obj;
obj.f(); //被访问的函数是 Y::f()
如果要访问基类中声明的名字,则应使用作用域标识符限定,例如:
obj.X::f();
例 2:在派生类中定义同名成员
#include<iostream>
#include<string>
using namespace std;
class Student{ //声明基类 Student
protected:
int num; //学号
string name; //姓名
float score; //成绩
public:
Student(int num1,string name1,float score1){ //基类构造函数
num=num1;
name=name1;
score=score1;
}
void print(){
cout<<"number:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"score:"<<score<<endl;
}
};
class Ustudent:private Student{ //声明私有派生类
private:
string major;
public:
Ustudent(int num1,string name1,float score1,string major1):Student(num1,name1,score1){ //定义派生类构造函数时,缀上基类的构造函数
major=major1;
}
void print(){
Student::print();
cout<<"major:"<<major<<endl;
}
};
int main(){
Ustudent stu(2018,"张值",100,"英语");
stu.print();
return 0;
}
执行结果:
二、访问声明
访问声明,可个别调整基类的某些成员,使之在派生类中保持原来的访问属性。访问声明的方法就是把基类的保护成员或公有成员直接写至私有派生类定义式中的同名段中,同时给成员名前冠以基类名和作用域标识符“ :: ”,这样的话,该成员就成为派生类的保护成员或公有成员了。
访问声明机制可以在私有派生类中个别调整从基类继承下来的成员性质,从而使外界可以通过派生类的界面直接访问基类的某些成员,同时也不影响其他基类成员的封闭性。
例 3:访问声明引入的原因
#include<iostream>
using namespace std;
class A{
private:
int x;
public:
A(int x1){
x=x1;
}
void print(){
cout<<"x="<<x;
}
};
class B:private A{
private:
int y;
public:
B(int x1,int y1):A(x1){
y=y1;
}
void print2(){ //通过派生类 B 的函数print2调用基类 A 的函数 print
print();
}
};
int main(){
B b(10,20);
b.print2();
return 0;
}
如果将私有派生类 B 中的语句
void print2(){ //通过派生类 B 的函数print2调用基类 A 的函数 print
print();
}
改为:
void print(){ A::print(); }
同时将主函数中稍作改变,程序运行结果不变。(用到了一中的同名成员)
但是这种方法在实际应用中却可能带来不便,有时程序员可能希望 A 的个别成员还能被派生类的对象直接访问,而不是通过派生类的公有成员函数间接访问。所以用到了访问声明:
class B:private A{
private:
int y;
public:
B(int x1,int y1):A(x1){
y=y1;
}
A::print; //访问声明
};
这样,基类 A 中 print 函数就调整成为派生类 B 的公有成员函数,外界就可以直接调用它了。
说明注意:
(1)数据成员也可以使用访问声明。
class A{
private:
```
public:
int x2;
```
};
class B:private A{
private:
```
public:
```
A::x2; //把基类中的 x2 调整为派生类的公有成员
```
};
(2)访问声明中只含不带类型和参数的函数名或变量名,即是
A::print;
而不能写成:
void A::print;
A::print();
void A::print();
(3)访问声明不能改变成员在基类中的访问属性,即,访问声明只能把原基类的保护成员调整为私有派生类的保护成员,把原基类的公有成员调整为私有派生类的公有成员,但对基类的私有成员不能使用访问声明。
(4)对于基类中的重载函数名,访问声明将对基类中所有同名函数起作用。所以对于重载函数使用访问声明要慎重。