C++中派生类和基类的转换和访问控制
来源:互联网 发布:抓取客户端数据工具 编辑:程序博客网 时间:2024/06/18 16:36
区分“派生类对象”和“派生类”对基类成员的访问权限。
l “派生类对象”对基类成员的访问权限:
(1)对于公有继承,只有基类的公有成员可以被“派生类对象”访问,其他(保护和私有)成员不能被访问。
(2)对于私有继承和保护继承,基类中所有成员都不能被“派生类对象”访问。
l “派生类”对基类中成员的访问权限:
(1)对于公有继承,基类中的公有成员和保护成员可以被“派生类”访问,而基类中的私有成员不能被访问。
(2)对私有继承和保护继承,也是基类中的公有成员和保护成员可以被“派生类”访问,而基类中的私有成员不能被访问。
在没有继承之前,类的只有两类用户:类本身和类的使用者。把类成员通过public和private划分恰好体现了这一分割:类的使用者只能访问类的public部分,它们一般是类的接口;而类成员则既可以访问public又可以访问private部分,private部分是类的具体实现。当有了继承之后,类的使用者多了一类:基类的派生类。派生类通常要访问基类的一些具体实现,而又不希望让一般的用户访问这些实现,所以就要把这些内容放置在一起,用protected标号来说明。从该类的使用者的角度,protected成员是私有的,你不能访问基类对象的保护成员,但是从该类的继承者的角度,protected则是共有的,因为他可以被继承下来供派生类使用。
为了更进一步限制派生类对基类成员的访问权限,C++又通过访问列表中的访问标号来控制。具体的说
1.如果继承方式为public,那么基类中的public成员在派生类总仍为public,基类中的protected仍为protected,基类中的private在派生类中不能被访问。
2.如果继承方式为protected,那么基类中的public成员在派生类中为protected,基类中的protected成员在派生类中为protected,基类的private成员在派生类中不能被访问。
3.如果继承方式为private,那么基类中的public成员在派生类中为private,基类中的protected成员在派生类中为private,基类的private成员在派生类中不可访问。
总结一下:
在c++的世界中有这样两个概念,向上类型转换,向下类型转换,分别描述的是子类向基类,和基类向子类的强制类型转换。
向上强制类型转换
切割:覆盖方法和子类数据丢失的现象生成切割(slice)
class Base{public: int b; virtual void Test() { cout << "base" <<endl; }};class Derived:public Base{public: int d; virtual void Test() { cout << "derived" <<endl; }};int main(){ Derived d; Base b = d;//直接赋值(产生切割) b.Test(); Base& b2 = d;//使用引用赋值(不产生切割) b2.Test(); Base* b3 = &d;//使用指针赋值(不产生切割) b3->Test(); return 1;}
因此,我们得出结论,在向上强制转换过程中,使用指针和引用不会造成切割,而使用直接赋值会造成切割。
再如如下一例子:
#include <iostream>using namespace std;class A{private:int x;public:A(){};virtual ~A(){};virtual void Fx(){cout<<"A, Fx()"<<endl;}void Fy(){cout<<"A, Fy()"<<endl;}};class B:public A{private:int y;public:B(){};~B(){};virtual void Fx()//重写{cout<<"B, Fx()"<<endl;}void Fy()//重定义{cout<<"B, Fy()"<<endl;}};int main(){B* pcb = new B();pcb->Fx(); A* pca = (A*)pcb;pca->Fx(); delete pcb;pca = new A();pcb = (B*)pca;pcb->Fx(); //第一处疑惑pcb->Fy(); //第二出疑惑delete pca;}
结果为:
B* pcb = new B();
pcb->Fx();
A* pca = (A*)pcb;
pca->Fx();
pcb->Fx(); //第一处疑惑:这个由于调用虚方法,所以是运行时多态,编译的时候看不出调的是哪个,运行时发现指针指向的是A对象,所以调用A的方法
pcb->Fy(); //第二出疑惑:这个由于调用普通方法,所以编译时就注定了会调用pcb所代表类型(B*)的方法,而不会管改指针所指向的对象模型(其实该指针指向的是A对象,只不过这个指针变量被强制转换成了B*,实际上并没有改变改指针的指向)
向下强制类型转换
使用dynamic_cast进行向下强制类型转换。使用此关键字有一下几个条件
1.必须有虚函数
2.必须打开编译器的RTTI开关(vc6: progect-> settings -> c/c++ tab ->category[c++ language]-> Enable RTTI)
3.必须有继承关系
Base *b = new Derived; Derived *d = dynamic_cast<Derived*>(b); if(!d) { cout << "dynamic cast err!"<<endl; } else { d->Test(); }
本例子中,符合以上条件,转换成功。否则,会抛出std::bad_cast异常,转换返回NULL
因此,我们可以使用dynamic_cast来判断两个类是否存在继承关系
class Window{public: std::string name() const; virtual void display() const { cout << "Window.display"; };}; class WindowWithScrollBars: public Window{public: virtual void display() const { cout << "WindowWithScrollBars.display"; };}; void printNameAndDisplay(Window w){ std::cout << w.name(); w.display();}<pre name="code" class="cpp" style="color: rgb(51, 51, 51);">//调用
WindowWithScrollBars wwsb;
printNameAndDisplay(wwsb);
//输出:
WindowWithScrollBars.display
void printNameAndDisplay(const Window &w){ std::cout << w.name(); w.display();}
http://blog.csdn.net/windows_nt/article/details/7415402
派生类访问基类的私有成员
派生类不能直接访问基类的私有成员,若要访问必须使用基类的接口,即通过其成员函数。实现方法有如下两种:
1.在基类的声明中增加保护成员,将基类中提供给派生类访问的私有成员定义为保护成员。
2.将需要访问基类私有成员的派生类成员函数声明为友元。
http://www.2cto.com/kf/201209/152686.html
派生类的构造函数问题
用户在声明类时可以不定义构造函数,系统会自动设置一个默认的构造函数,在定义类对象时会自动调用这个默认的构造函数。这个构造函数实际上是一个空函数,不执行任何操作。如果需要对类中的数据成员初始化,应自己定义构造函数。
构造函数的主要作用是对数据成员初始化。基类的构造函数是不能继承的,在声明派生类时,派生类并没有把基类的构造函数继承过来,因此,对继承过来的基类成员初始化的工作也要由派生类的构造函数承担。所以在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还应当考虑基类的数据成员初始化。 也就是说,希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。解决这个问题的思路是,在执行派生类的构造函数时,调用基类的构造函数。
任何派生类都包含基类的成员,简单的派生类只有一个基类,而且只有一级派生(只有直接派生类,没有间接派生类),在派生类的数据成员中不包含基类的对象(即子对象)。
#include <iostream>#include<string>using namespace std;class Student//声明基类Student{ public: Student(int n,string nam,char s) //基类构造函数 { num=n; name=nam; sex=s; } ~Student( ){ } //基类析构函数 protected : //保护部分 int num; string name; char sex ;};class Student1: public Student //声明派生类Student1{ public : //派生类的公用部分 Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)//派生类构造函数 { age=a; //在函数体中只对派生类新增的数据成员初始化 addr=ad; } void show( ) { cout<<"num: "<<num<<endl; cout<<"name: "<<name<<endl; cout<<"sex: "<<sex<<endl; cout<<"age: "<<age<<endl; cout<<"address: "<<addr<<endl<<endl; } ~Student1( ){ } //派生类析构函数 private : //派生类的私有部分 int age; string addr;};int main( ){ Student1 stud1(10010,"Wang-li",'f',19,"115 Beijing Road,Shanghai"); Student1 stud2(10011,"Zhang-fun",'m',21,"213 Shanghai Road,Beijing"); stud1.show( ); //输出第一个学生的数据 stud2.show( ); //输出第二个学生的数据 return 0;}
Student1(int n, string nam, char s, int a, string ad);
Student :: Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s){ age=a; addr=ad;}
Student1(int n, string nam,char s,int a, string ad):Student(n,nam,s){ age=a; //在函数体中对派生类数据成员初始化 addr=ad;}
Student1(int n, string nam,char s,int a, string ad):Student(n,nam,s),age(a),addr(ad){}
#include<stdio.h>class BaseClass{public: BaseClass(int ValPl = 1, int ValPt = 2, int ValPr = 3 ):iValPulic(ValPl),iValProtected(ValPt),iValPrivate(ValPr){ printf("BaseClass Inital\n");} ~BaseClass(){ printf("BaseClass UnInitial\n"); }; int iValPulic; int GetPublicVal(){ return 1; } int GetProtectedVal(){ return iValProtected; }; int GetPrivateValPublic(){ return iValPrivate; };protected: int iValProtected; int GetPrivateVal(){ return iValPrivate; };private: int iValPrivate;};class DriveClass:public BaseClass{public: int iDrivePublic; DriveClass(int iValDrive, int ValPl, int ValPt, int ValPr ):iDrivePublic(iValDrive),BaseClass(ValPl, ValPt, ValPr){ printf("DriveClass Inital\n"); } ~DriveClass(){ printf("DriveClass UnInitial\n"); } int GetPublicVal(){ return iValPulic; } int GetPublicValSELECT(){ return this->GetPublicVal(); } int GetPublicValBase(){ return BaseClass::GetPublicVal(); } int GetProtectedVal(){ return iDrivePublic; } int GetBaseProtectedVal(){ return GetPrivateValPublic(); };};int main(){ BaseClass BSClassObject(1,2,3); printf("GetProtectedVal = %d, iValPulic = %d\n",BSClassObject.GetProtectedVal(), BSClassObject.iValPulic); DriveClass DRClass(4,5,6,7); printf("GetProtectedVal = %d, GetBaseProtectedVal = %d\n",DRClass.GetProtectedVal(), DRClass.GetBaseProtectedVal()); printf("GetPublicValSELECT = %d, GetPublicValBase = %d\n",DRClass.GetPublicValSELECT(), DRClass.GetPublicValBase()); return 0;}
再来看一个例子:
//基类class Base{public:Base(int i = 0):baseVal_public(i),baseVal_protected(i),baseVal_private(i){}int baseVal_public;void printVal(){cout<<baseVal_protected<<endl;cout<<baseVal_private<<endl;};protected:int baseVal_protected;private:int baseVal_private;};//派生类class Derived_public:public Base{public:Derived_public(int i = 0):Base(i){}void getVal(){//基类的公有成员在派生类中仍未为公有cout<<baseVal_public<<endl;//基类受保护成员变仍未受保护成员cout<<baseVal_protected<<endl;//基类的私有成员不能被派生类继承//cout<<baseVal_private<<endl;}};class Derived_protected:protected Base{public:Derived_protected(int i = 0):Base(i){}void getVal(){//基类的共有成员、受保护成员变为受保护成员cout<<baseVal_public<<endl;cout<<baseVal_protected<<endl;//基类私有成员不能被派生类继承//cout<<baseVal_private<<endl;}};class Derived_private:private Base{public:Derived_private(int i = 0):Base(i){}void getVal(){//基类的公有成员、受保护成员变为派生类的私有成员cout<<baseVal_public<<endl;cout<<baseVal_protected<<endl;//基类的私有成员不能被继承//cout<<baseVal_private<<endl;}};int main(){Base b;//公有成员可以被用户访问cout<<b.baseVal_public<<endl;//私有成员、受保护成员不能被用户访问//cout<<b.baseVal_private<<endl;//cout<<b.baseVal_protected<<endl;//私有成员、受保护成员可以被类成员访问b.printVal();//公有继承下Derived_public d1;//基类的public成员仍为public,可以访问cout<<d1.baseVal_public<<endl;//私有成员,受保护成员仍为私有、受保护,不能访问//cout<<d1.baseVal_protected<<endl;//cout<<d1.baseVal_private<<endl;d1.getVal();//受保护继承Derived_protected d2;//基类的public变为派生类的protected//cout<<d2.baseVal_public<<endl;//基类的protected变为派生类的protected//cout<<d2.baseVal_protected<<endl;//基类的private不能被继承//cout<<d2.baseVal_private<<endl;d2.getVal();//私有继承Derived_private d3;//基类的公有成员、受保护成员变为派生类的私有//cout<<d3.baseVal_public<<endl;//cout<<d3.baseVal_protected<<endl;//私有成员不能被继承//cout<<d3.baseVal_private<<endl;d3.getVal();return 0;}
class Derived_private:private Base{public:Derived_private(int i = 0):Base(i){}void getVal(){//基类的公有成员、受保护成员变为派生类的私有成员cout<<baseVal_public<<endl;cout<<baseVal_protected<<endl;//基类的私有成员不能被继承//cout<<baseVal_private<<endl;}<div><span style="color: rgb(51, 51, 51);"><span data-wiz-span="data-wiz-span"><span style="font-size:14px;">using Base::baseVal_public1;</span></span></span></div><div><span style="color: rgb(51, 51, 51);"><span style="font-size:14px;"></span></span></div><div><span style="color: rgb(51, 51, 51);"><span data-wiz-span="data-wiz-span"><span style="font-size:14px;">};</span></span></span></div>
cout<<d3.baseVal_public1<<endl;
还有一点需要注意的,就会友元关系在继承和派生以后会发生什么变化。
总的来说,分为两点:1.如果一个类被授予为另一个类的友元,它的派生类并不不是这个类的友元。2.基类的友元对基类的派生类不起作用。举个例子来说明:
//基类 class Base { friend class Frnd; public: Base(int i = 0):baseVal_private(i){} private: int baseVal_private; }; class D1:public Base { private: int derivedVal; }; class Frnd { public: int mem(Base b){return b.baseVal_private;} //基类的友元对派生类来说不起作用 //int mem(D1 d){return d.derivedVal;} }; class D2:public Frnd { public: //友元类的派生类不再是授予有缘的那个类的友元 //int mem(Base b){return b.baseVal_private;} };
最后有一点需要注意,如果你使用的是class定义的派生类,那么如果不写访问标号,那么默认继承关系为private;如果使用struct定义的派生类,不写访问标号,则默认继承关系为public。
- C++中派生类和基类的转换和访问控制
- [c++]派生类的访问控制
- C++ virtual 与"基类"和"派生类"的访问控制
- C++类的继承和派生,访问控制
- C++中派生类的访问控制
- 派生类的访问控制
- 派生类到基类的转换 和基类到派生类的转换
- 派生类到基类的转换 和基类到派生类的转换
- 派生类到基类的转换 和基类到派生类的转换
- c++模板类派生:派生类访问基类中的public 和protected成员的一些问题
- 类型转换-基类和派生类之间的转换
- 基类和派生类的成员访问
- 基类和派生类的成员访问
- 基类和派生类的各种访问
- 区分“派生类对象”和“派生类”对基类成员的访问权限
- 派生类的三种访问控制
- 命名白白c++ 基类和派生类的转换
- 派生类对基类成员的访问权限和派生类对象对基类成员的访问权限
- Max space clustering (Hamming)
- HTTP Content-type对照表
- 移动端页面性能探究
- Android:静态注册BroadcastReceiver
- rgba()和opacity的比较
- C++中派生类和基类的转换和访问控制
- 用Java代码删除一个已排好序链表中重复的数字
- 基于V4L2 MFC 视频编解码
- ZOJ 2954 Hanoi Tower(模拟啊 )
- 一个程序员的慢慢爬坑之路吧。。
- JavaIO编程之ReadLine
- 集群管理笔记
- 一五年四月六日
- C语言初级语法终章--位运算