c++中的private/protect/public & virtual

private:

私有控制符。这类成员只能被本类中的成员函数和类的友元函数访问。

protected:

受保护控制符。这类成员可以被本类中的成员函数和类的友元函数访问,也可以被派生类的成员函数和类的友元函数访问。

public:

共有控制符。这类成员可以被本类中的成员函数和类的友元函数访问,也可以被类作用域内的其他函数引用。

virtual:

C++通过虚函数实现多态."无论发送消息的对象属于什么类,它们均发送具有同一形式的消息,对消息的处理方式可能随接手消息的对象而变"的处理方式被称为多态性。而虚函数是通过Virtual关键字来限定的。

只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现。

虚函数是在类中被声明为virtual的成员函数,当编译器看到通过指针或引用调用此类函数时,对其执行晚绑定。

1.
public / protected / private / virtual

c++中,成员默认为private访问权限。
structure中,成员默认为public访问权限。
二者都支持继承/构造/析构等。
对象是类的实例化。成员函数对于整个类而言却是被所有的实例化的类对象共享的,即一个类只保留一份成员函数。 每一个实例对象都只是对其中的数据成员初始化,内存映像中每个对象仅仅保留属于自己的那份数据成员副本。
那么每个对象怎样和这些可以认为是“分离”的成员函数发生联系,即成员函数如何操作对象的数据成员?记住this指针,无论对象通过(.)操作或者(->)操作调用成员函数,编译时刻,编译器都会将这种调用转换成我们常见的全局函数的形式,并且多出一个参数(一般这个参数放在第一个),然后将this指针传入这个参数。于是就完成了对象与成员函数的绑定(或联系)。
类的定义使用到三种访问修饰符private/public/protected,它们要控制的是一个函数对一个类的成员(包括成员变量及成员方法)的访问权限。

private: 只能由该类中的函数、其友元函数访问,除此之外的用户程序都不能通过类对象对其进行访问;
protected: 可以被该类中的函数、子类的函数(public继承下)、以及其友元函数访问,除此之外的用户程序都不能通过类对象对其进行访问;
public: 可以被该类中的函数、子类的函数(public继承下)、其友元函数访问,在用户程序中也可以由该类的对象对其进行访问。

总结起来就是:

一个类友元(包含友元函数或者友元类的所有成员函数)可以访问该类的任何成员(包括成员变量及成员方法)。
除去友元外,private成员只有该类自身的成员函数可以访问,protected成员只有该类的成员函数及其派生类的成员函数可以访问,public成员则所有的函数都可以访问。

类的成员,不管使用哪种访问修饰符,都必须通过类的对象进行访问。即使是在类的成员函数内部,访问的数据也是通过类对象进行的,每个成员函数默认的第一个形参为this指针,其中访问的数据成员全部是由“this->”这种方式进行的,只是默认情况下都省略了而已。C++的访问修饰符的作用是以类为单位,而不是以对象为单位。通俗的讲,同类的对象间可以“互相访问”对方的数据成员,只不过访问途径不是直接访问。

2. 类继承后成员访问属性变化:

使用private继承,父类的所有成员在子类中变为private;
使用protected继承,父类的protected和public成员在子类中变为protected,private成员不变;
使用public继承,父类中的方法属性不发生改变。

经过类的继承以后,基类的成员可以理解为:成为了继承类的成员,只是要做相应的访问属性改变,虽然基类成员好像是成为了继承类成员,但是还是和本身继承类数据成员有区别的,例如:继承类成员函数是不能访问继承过来的基类的私有成员,但可以访问继承过来的公有和保护成员。

3. virtual保留字

这里我们要讲的多态是指生效于运行时的动态多态,C++的动态多态技术是基于继承机制和虚函数的。多态可以理解成:不同的动作行为可以与同一个记号相关联。通俗的讲:基类类型的指针或引用可以调用基类的函数,也可以执行继承类的函数。这里的函数调用必须有个动态绑定,要实现这种动态绑定必须满足两个条件:

只有指定为虚函数的成员函数才能进行动态绑定;
必须通过基类类型的指针或者引用进行函数调用。

引用和指针的静态类型和动态类型可以不同,这是C++用以支持多态性的基石。因为每个派生类对象都包含基类部分,所以可以用基类类型的引用绑定到派生类对象的基类部分,也可以用基类类型的指针指向派生类对象(但是不能用继承类类型引用或指针绑定基类对象,除非强制类型转换)。基类类型的引用或者指针在编译就是可知的,这是静态类型,但是的它们所绑定的对象类型在运行时才可知,而且可能与的它们的静态类型不同,所以它们最终绑定的类型就是动态类型。

要理解多态中的动态绑定,首先要理解C++如何在继承层次中确定函数调用:

首先确定进行函数调用的对象、引用或指针的静态类型;
在该类中查找和调用的函数名字相同(不管参数)的函数,如果找不到,就在该类的直接基类中查找,如此循着它继承链往上找,直到找到名字相同的函数或者找完最后一个类,如果不能在类或者其他基类中找到该名字,则调用是错误的;
一旦在某个类中找到一个和待调用的函数名字相同的函数,则在这个类中查找所有这个名字的函数重载版本,看能否找到一个能与待调用函数实参类型相同的函数,不能找到则调用不合法;(前三个步骤是在编译的时候确定)
如果函数调用合法,如果函数是虚函数,且通用引用或者指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则编译器生成代码直接调用函数。

单纯从virtual关键字出发,考虑两层关系:一个基类一个继承类,使用基类类型引用或者指针进行函数调用,首先在基类中查找一个能与待调用函数实参类型相同的函数,如果找不到,则调用出错;如果找到,看该函数是否是虚函数,如果基类中该函数是虚函数,而且继承类中有相同原型的函数,即使没有用virtual保留字,继承类中的函数自动变成虚函数,然后再运行过程中根据基类指针或引用绑定的对象来调用相应的函数,如果继承类中没有相同原型的函数,即使运行时绑定的是继承类对象,那么还是调用基类中的函数。

 


 

原文转载地址:

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。