对于子类和父类如果拥有同名的data member 或者non virtual 成员函数,会如何处理?如果data member是static类型的又有何不同?(实际上体现了对继承的深刻理解)
对于这样的同名non virtual 函数或者 成员,实际上由指针或者对象的类型决定了访问的具体是哪个?如果使用子类类型的对象或指针,则只能看到子类里的哪个函数或者成员,对于父类里的函数则会产生遮蔽(隐藏)现象(任何时候子类中重新定义了基类中的函数,基类中所有同名的重载函数都自动隐藏了),如果想访问父类成员,必须加上父类的名称限定,【实现模型】也就是说实际上编译器在实现中自动地对这种重名现象进行了处理,给父类对象加上了一个限定词合成了一个新的名称。但是如果没有发生这种重名现象,子类类型的对象或指针,依然可以正常访问从父类继承下来的那些成员。 static
数据成员也同理。
如果使用基类类型的对象或指针(即使用派生类对象地址来初始化),则永远只能看到基类里的函数和成员,不能显示访问子类的对象。
class Base
{
public:
Base():a(1){}
virtual void func() {cout<<"Base"<<endl;}
int f() const{
cout<<"Base::f()\n";
return 1;
}
int f(string str) const {cout<<str<<endl; return 1;}
int a;
static int s;
};
class Derive : public Base
{
public:
Derive():a(2){}
void func() {cout<<"Derive"<<endl;}
/*
int f() const{
cout<<"Derive::f()\n";
return 1;
}
*/
void f() const{
cout<<"void f() \n";
}
// 上面的两个f()不能同时存在一个类中,因为无法重载仅按返回类型区分的non-virtual函数;可放在其他从Base派生的类中
int a;
static int s;
};
int Base::s = 0; //static变量初始化
int Derive::s = 1;
int main()
{
Derive d;
Derive *pa = &d;
//一般成员变量
cout<<pa->a<<endl; //pa为Derive类型,由于基类和派生类有同名的a, 对基类中的a会隐藏,实际上是给父类的对象a加上了一个限定词。默认访问的是Derive类中的a = 2
cout<<pa->Base::a<<endl; // 若想访问基类的a,必须显示指定
//static member
cout<<pa->s<<endl; ///pa为Derive类型,对基类中的静态成员s隐藏,默认访问Derive的s
cout<<pa->Base::s<<endl; //显示访问Base的s
//member function
pa->f(); // pa为Derive类型,Derive对f进行了重新定义,隐藏了基类中的所有f的重载版本;默认访问Derive的f
pa->Base::f(); //显示访问Base的f
// !!! pa->f("abc"); //派生类对non-virtual 函数进行改写(重新定义或参数列表,返回值改变)时,派生类中的函数会隐藏基类中的所有重载版本!!因此,不能访问基类的f(string){};
pa->Base::f("abc"); //只能通过显示访问被隐藏的Base::f(string)
Base *pb = &d;
cout<<pb->a<<endl; //pb为Base类型,默认且只能访问Base类中的a = 1;
cout<<pb->s<<endl;
//!!! cout<<pb->Derive::a<<endl; // 出错,提示限定名不是Base或其基类的成员。因为父类指针pb是无法访问子类里的public成员变量或者函数的
//可以使用强制转换static_cast<Derive*>(pb)实现;
cout<<static_cast<Derive*>(pb)->s<<endl; //pb强制转换为Derive型后,和pa一样,默认访问的是Derive的a = 2;
cout<<pb->a<<endl; //此时上面的转换失效,pb仍然还是Base* 类型。
cout<<pb->s<<endl;
pb->f(); //
pb->f("123");
//!!! pb->Derive::f(); //显示访问Derive的f,错误,pb为Base*,不能访问Derived的成员
system("pause");
return 0;
}