继承,封装,多态
C++三个最基本面向对象的的特征
封装:主要是对数据以及操作封装为一个整体,提供统一的接口操作,隐藏细节实现。防止破坏数据以及方便代码重用。
继承:即从一般都特殊,保留现有的功能的基础上对原有类进行功能和属性的扩展
多态:具体分为两种
1)重载:主要是函数名相同而参数个数,类型不同进行重载
2)覆盖或重写:主要是子类对虚函数进行重写。只有这个是面向对象编程的概念。简单的说就是可以通过基类指针指向子类对象的地址来实现虚函数调用。在C++中类对象内存 主要分为类成员变量内存,如果有虚函数则增加一个指向虚函数表地址的指针内存。
目前还有基于对象的编程方法:不提供继承也就没有多态,只提供对象,以及相应的方法,比如object-c
c++实现多态的方法
面向对象有了一个重要的概念就是对象的实例,对象的实例代表一个具体的对象,故其肯定有一个数据结构保存这实例的数据,这一数据包括对象成员变量,如果对象有虚函数方法或存在虚继承的话,则还有相应的虚函数或虚表指针,其他函数指针不包括。
虚函数在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)
浙公网安备 33010602011771号