C++ encapsulation, inheritance, polymorphism

Original source http://blog.csdn.net/ruyue_ruyue/article/details/8211809


C++ package inheritance polymorphism summary

Three basic characteristics of object-oriented

The three basic characteristics of object-oriented are: encapsulation, inheritance, and polymorphism . Among them, encapsulation can hide implementation details and make code modular; inheritance can extend existing code modules (classes); their purpose is-code reuse. And polymorphism is to achieve another purpose-interface reuse!

Package                                                                                                                                                                   

What is encapsulation?

Encapsulation can hide the implementation details and make the code modular; encapsulation is to surround the process and data, and access to the data can only be through a defined interface . Object-oriented computing begins with the basic concept that the real world can be depicted as a series of fully autonomous, encapsulated objects that access other objects through a protected interface . In object-oriented programming, it can be understood as: encapsulating objective things into abstract classes, and classes can only operate their own data and methods for trusted classes or objects, and hide untrusted information.

inherit                                                                                                                                                                      

What is inheritance?

Inheritance refers to the ability: it can use all the functions of the existing class and extend these functions without rewriting the original class. The process of its inheritance is the process from general to special.

New classes created through inheritance are called " subclasses " or " derived classes ". The inherited class is called the " base class " , " parent class " or " super class " . To achieve inheritance, it can be achieved through " inheritance " ( Inheritance ) and " composition " ( Composition ). In some  OOP  languages, a subclass can inherit multiple base classes. But under normal circumstances, a subclass can only have one base class. To achieve multiple inheritance, it can be achieved through multiple inheritance.

How to implement inheritance?

There are three ways to implement the concept of inheritance: implementation inheritance, interface inheritance and visual inheritance .

1.  Implementation inheritance refers to the ability to use the attributes and methods of the base class without additional coding;

2.  Interface inheritance means that only the names of attributes and methods are used, but the subclass must provide the ability to implement;

3.  Visual inheritance refers to the ability of sub-forms (classes) to use the appearance of base forms (classes) and to implement codes.

Polymorphism                                                                                                                                             

What is polymorphism?

Polymorphism (polymorphisn) is a technology that allows you to set the parent object to be equal to one or more of its child objects. After assignment, the parent object can operate in different ways according to the characteristics of the child object currently assigned to it . Simply put, it is one sentence: It is allowed to assign a pointer of a subclass type to a pointer of a parent type .

Example: (2012 a ** software company written test questions)

Please write the output results of the following code in order:

Answer: call child func

call ~child

call ~base

Analysis of the realization of polymorphism?

There are two ways to achieve polymorphism, covering and overloading. Override : refers to the practice of redefining the virtual function of the parent class by the subclass. Overloading : It means that multiple functions with the same name are allowed, and the parameter lists of these functions are different (perhaps the number of parameters is different, or the parameter types are different, or both are different).

analysis:

" Overload " refers to the same return type and method name in the same class, but the number and types of parameters can be different

" Overwrite\ rewrite" is in a different class.

其实,重载的概念并不属于面向对象编程,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_funcstr_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!真正和多态相关的是覆盖。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关!引用一句Bruce Eckel的话:不要犯傻,如果它不是晚邦定,它就不是多态。

C++多态机制的实现:

该部分转自:http://blog.chinaunix.net/uid-7396260-id-2056657.html

1c++实现多态的方法

面向对象有了一个重要的概念就是对象的实例,对象的实例代表一个具体的对象,故其肯定有一个数据结构保存这实例的数据,这一数据包括对象成员变量,如果对象有虚函数方法或存在虚继承的话,则还有相应的虚函数或虚表指针,其他函数指针不包括。

虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,每个类的对象用了一个虚指针。要讲虚函数机制,必须讲继承,因为只有继承才有虚函数的动态绑定功能,先讲下c++继承对象实例内存分配基础知识:

从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,每个类的对象用了一个虚指针。具体的用法如下:
class A
{public:
    virtual void f();
    virtual void g();
private:
    int a
};

class B : public A
{
public:
    void g();
private:
    int b;
};
//A,B的实现省略
因为A有virtual void f(),和g(),所以编译器为A类准备了一个虚表vtableA,内容如下:

 

A::f 的地址

A::g 的地址

B因为继承了A,所以编译器也为B准备了一个虚表vtableB,内容如下:

A::f 的地址

B::g 的地址

注意:因为B::g是重写了的,所以B的虚表的g放的是B::g的入口地址,但是f是从上面的A继承下来的,所以f的地址是A::f的入口地址。然后某处有语句 B bB;的时候,编译器分配空间时,除了A的int a,B的成员int b;以外,还分配了一个虚指针vptr,指向B的虚表vtableB,bB的布局如下:

vptr : 指向B的虚表vtableB

int a: 继承A的成员

int b: B成员


当如下语句的时候:
A *pa = &bB;
pa的结构就是A的布局(就是说用pa只能访问的到bB对象的前两项,访问不到第三项int b)
那么pa->g()中,编译器知道的是,g是一个声明为virtual的成员函数,而且其入口地址放在表格(无论是vtalbeA表还是vtalbeB表)的第2项,那么编译器编译这条语句的时候就如是转换:call *(pa->vptr)[1](C语言的数组索引从0开始哈~)。
这一项放的是B::g()的入口地址,则就实现了多态。(注意bB的vptr指向的是B的虚表vtableB)
另外要注意的是,如上的实现并不是唯一的,C++标准只要求用这种机制实现多态,至于虚指针vptr到底放在一个对象布局的哪里,标准没有要求,每个编译器自己决定。我以上的结果是根据g++ 4.3.4经过反汇编分析出来的。
2、两种多态实现机制及其优缺点

除了c++的这种多态的实现机制之外,还有另外一种实现机制,也是查表,不过是按名称查表,是smalltalk等语言的实现机制。这两种方法的优缺点如下:
(1)按照绝对位置查表这种方法由于编译阶段已经做好了索引和表项(如上面的call *(pa->vptr[1]) ),所以运行速度比较快;缺点是:当A的virtual成员比较多(比如1000个),而B重写的成员比较少(比如2个),这种时候,B的vtableB的剩下的998个表项都是放A中的virtual成员函数的指针,如果这个派生体系比较大的时候,就浪费了很多的空间。
比如:GUI库,以MFC库为例,MFC有很多类,都是一个继承体系;而且很多时候每个类只是1、2个成员函数需要在派生类重写,如果用C++的虚函数机制,每个类有一个虚表,每个表里面有大量的重复,就会造成空间利用率不高。于是MFC的消息映射机制不用虚函数,而用第二种方法来实现多态,那就是:
(2)、按照函数名称查表,这种方案可以避免如上的问题;但是由于要比较名称,有时候要遍历所有的继承结构,时间效率性能不是很高。(关于MFC的消息映射的实现,看下一篇文章)
3、总结:
如果继承体系的基类的virtual成员不多,而且在派生类要重写的部分占了其中的大多数时候,用C++的虚函数机制是比较好的;但是如果继承体系的基类的virtual成员很多,或者是继承体系比较庞大的时候,而且派生类中需要重写的部分比较少,那就用名称查找表,这样效率会高一些,很多的GUI库都是这样的,比如MFC,QT
PS 其实,自从计算机出现之后,时间和空间就成了永恒的主题,因为两者在98%的情况下都无法协调,此长彼消;这个就是计算机科学中的根本瓶颈之所在。软件科学和算法的发展,就看能不能突破这对时空权衡了。呵呵
何止计算机科学如此,整个宇宙又何尝不是如此呢?最基本的宇宙之谜,还是时间和空间~


Guess you like

Origin blog.csdn.net/gouguofei/article/details/50328737