一:继承中的访问权限关系。
1.基类,父类,超类是指被继承的类,派生类,子类是指继承于基类的类.
2.在C++中使用:冒号表示继承,如class A:public B;表示派生类A从基类B继承而来
3.派生类包含基类的所有成员,而且还包括自已特有的成员,派生类和派生类对象访问基类中的成员就像访问自已的成员一样,可以直接使用,不需加任何操作符,但派生类仍然无法访问基类中的私有成员.
4.在C++中派生类可以同时从多个基类继承,Java 不充许这种多重继承,当继承多个基类时,使用逗号将基类隔开.
5.基类访问控制符,class A:public B 基类以公有方式被继承,A:private B 基类以私有方式被继承,A:protected B 基类以受保护方式被继承,如果没有访问控制符则默认为私有继承。
6. protected 受保护的访问权限;使用protected 保护权限表明这个成员是私有的,但在派生类中可以访问基类中的受保护成员。派生类的对象就不能访问受保护的成员了。
7. 如果基类以public 公有方式被继承,则基类的所有公有成员都会成为派生类的公有成员.受保护的基类成员成为派生类的受保护成员.
8.如果基类以private 私有被继承,则基类的所有公有成员都会成为派生类的私有成员.基类的受保护成员成为派生类的私有成员.
9.如果基类以protected 受保护方式被继承,那么基类的所有公有和受保护成员都会变成派生类的受保护成员.
10.不管基类以何种方式被继承,基类的私有成员,仍然保有其私有性,被派生的子类不能访问基类的私有成员.
例:继承中的访问权限关系
class A {int a; protected:int b; public:int c; A(){a=b=c=1;} };
//类B以公有方式从基类A继承
class B:public A
{public: int d;
B(){//a=2; //错误,不能访问基类中的私有成员,因为a=2已经默认为私有保护了。
b=2; //正确,可以在类中访问基类中的受保护成员,但类的对象不能访问,基类中的受保护成员b在类B中仍然是受保护成员
c=d=2;} }; //基类中的公有成员c在类B中仍然是公有成员
//以受保护和私有方式从基类A继承。
class C:protected A {public: int e; C(){//a=3; //错误,不能访问基类中的私有成员
b=c=e=3; }};//这里基类受保护成员b和公有成员c都成为类C中的受保护成员。
class D:private A {public: D(){b=c=4;} };//基类中的公有和受保护成员都成为了类D中的私有成员。
//验证受保护和私有方式继承的访问权限。
class C1:public C
{public: C1(){b=c=e=4;} };//正确;类A中的成员b和c在类C中是以受保护方式被继承的,b和c都成为了类C中的受保护成员。
class D1:public D
{public:D1(){//b=5; //错误,在A中受保护的成员b在类D中是以私有方式继承的,这样b就成为了类D中的私有成员,所以无法访问。
//c=5; //错误,在A中公有的成员c在类D中是以私有方式继承的,这样c就成为了类D中的私有成员,所以无法访问。} };
int main()
{A m1; B m2; C m3; D m4;
//cout<<m1.b<<m2.b<<m3.b<<m4.b; //错误;不能用类的对象访问受保护的成员,只有在类中才能访问。
cout<<m1.c; cout<<m2.c;
//cout<<m3.c; //错误,类C是以受保护的方式从A继承的,基类中的变量c在类C中就是受保护的,所以类的对象不能访问
//cout<<m4.c; //错误,类C是以私有的方式从A继承的,基类中的变量c在类C中就是私有的,所以类的对象不能访问
}
二:覆盖和隐藏基类成员变量或成员函数。
1. 基类的成员变量或函数被覆盖:如果派生类覆盖了基类中的成员函数或成员变量,则当派生类的对象调用该函数或变量时是调用的派生类中的版本,当用基类对象调用该函数或变量时是调用的基类中的版本。
2. 隐藏基类成员函数的情况:如果在派生类中定义了一个与基类同名的函数,不管这个函数的参数列表是不是与基类中的函数相同,则这个同名的函数就会把基类中的所有这个同名的函数的所有重载版本都隐藏了,这时并不是在派生类中重载基类的同名成员函数,而是隐藏,比如类A中有函数f(int i,intj)和f(int i)两个版本,当在从A派生出的类B中定义了基类的f()函数版本时,这时基类中的f(int i)和f(int i,int j)就被隐藏了,也就是说由类B创建的对象比如为m,不能直接访问类A中的f(int i)版本,即使用语句m.f(2)时会发生错误。
3. 怎样使用派生类的对象访问基类中被派生类覆盖或隐藏了的函数或变量:
3.1. 方法1 使用作用域运算符::,在使用对象调用基类中的函数或变量时使用作用域运算符即语句m.A::f(2),这时就能访问基类中的函数或变量版本。注意,访问基类中被派生类覆盖了的成员变量只能用这种方法。
3.2. 方法2 使用using:该方法只适用于被隐藏或覆盖的基类函数,在派生类的类定义中使用语句using 把基类的名字包含进来,比如using A::f;就是将基类中的函数f()的所有重载版本包含进来,重载版本被包含到子类之后,这些重载的函数版本就相当于是子类的一部分,这时就可以用派生类的对象直接调用被派生类隐藏了的基类版本,比如m.f(2),但是使用这种语句还是没法调用基类在派生类中被覆盖了的基类的函数,比如m.f()调用的是派生类中定义的函数f,要调用被覆盖的基类中的版本要使用语句m.A::f()才行。
4. 在派生类的函数中调用基类中的成员变量和函数的方法:就是在函数中使用的被派生类覆盖的基类成员变量或函数前用作域解析符加上基类的类名,即a::f()就是在派生类的函数中调用基类中被派生类覆盖了的函数f()的方法。
5. 派生类以私有方式被继承时改变基类中的公有成员为公有的方法:
5.1.使用::作用域运算符,不提倡用这种方法,在派生类的public 后面用作用域运算符把基类的公有成员包函进来,这样基类的成员就会成为派生类中的公有成员了,注意如果是函数的话后面不能加括号,如A::f;如果f是函数的话不能有括号。
5.2.使用using语句,现在一般用这种方法,也是在派生类的public使用using把基类成员包函进来,如using A::f。