面向对象:封装、继承、多态

概念太多,总结一下,备忘。

1.三大特性

封装

隐藏对象的属性和实现细节,仅对外提供公共访问方式。

继承

代码重用,子类继承父类的函数

构造函数的覆盖:
(1)父类没有构造函数或只有无参构造函数。
子类无需显示调用父类的构造函数,系统自动在调用子类构造函数前调用父类的构造函数。
(2)父类只有有参构造函数
子类必须显示调用父类构造函数
(3)父类有无参和有参的构造函数
子类不显示调用父类构造函数时,系统默认调用父类无参构造函数。

拷贝构造函数:用基于同一类的一个对象构造和初始化另一个对象
CExample(const CExample& C)
调用时机:
(1)一个对象以值传递的方式传入函数体
(2)一个对象以值传递的方式从函数返回
(3)一个对象需要通过另一个对象进行初始化

Class A{
    A (const A& a){//拷贝构造函数
        this.x = a.x;
    }
};
void fun1(A a){//(1)对象以值传递的方式传入函数体
    cout<<a.x<<endl;
}
A fun2(int x){//(2)对象以值传递的方式从函数返回
    A a(x);
    return a;
}
A a;
A b(a);//(3)对象需要通过另一个对象进行初始化
A b=a;//(3)对象需要通过另一个对象进行初始化

多态

多态分为:编译时多态运行时多态。区别在于函数地址是编译时绑定还是运行时绑定。

编译时多态:
通过函数重载实现。

运行时多态:
通过虚函数实现。
核心理念就是通过基类访问派生类定义的函数。
将子类类型的指针赋值给父类类型的指针,只能访问子父类共有的方法,不能访问子类特有的方法。
而且只有虚函数是调用子类的(虚函数表),其他函数依旧调用父类的(地址偏移量固定)

2.虚函数vs纯虚函数

虚函数

主要作用是“运行时多态”。virtual void fun()
使用virtual关键字的父类函数。子类可以重写父类的虚函数来实现子类的特殊化。

纯虚函数

在基类中声明的虚函数,没有定义,virtual void fun()=0
声明了纯虚函数的类是一个抽象类,不能实例化,只能作为基类。
子类中重新声明函数,不要后面的=0

3.重载(overload)、覆盖(override)、隐藏

重载:“让类以统一的方式处理不同类型数据的一种手段”

同一个类中
函数名相同
参数列表不同

覆盖:“子类在继承父类时,重写(重新实现)父类中的方法”

不同类中
父类中的方法有virtual关键字,并且非私有
函数名相同
参数列表相同
返回类型相同
作用域只能扩大(public>protected>private)

隐藏:“子类的函数屏蔽了同名的父类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。”

不同类中
函数名相同
没有virtual修饰

4.虚函数表

虚函数是通过虚函数表实现的。虚函数表(virtual table)实现原理参考了博客C++ 虚函数表解析

首先明确:
1)只有包含虚函数的类才会有虚函数表
2)同属于一个类的对象实例共享虚函数表
3)虚函数表实际上是一个指针数组,存放了虚函数的地址。
4)为了保证效率,虚函数表指针存在对象实例的最前面的位置。

总结几种情况:

//基类
class Base {
     public:
            virtual void f() { cout << "Base::f" << endl; }
            virtual void g() { cout << "Base::g" << endl; }
            virtual void h() { cout << "Base::h" << endl; }

};

基类的虚函数表
这里写图片描述

(1)一般继承(无虚函数覆盖)

class Derive:public Base {
     public:
            virtual void f1() { cout << "Derive::f1" << endl; }
            virtual void g1() { cout << "Derive::g1" << endl; }
            virtual void h1() { cout << "Derive::h1" << endl; }

};

派生类没有重写基类的任何虚函数,派生类的虚函数表为:
这里写图片描述
注意:
1)虚函数按照声明顺序放在表中
2)基类虚函数在派生类虚函数前面

(2)一般继承(有虚函数覆盖)

class Derive:public Base {
     public:
            void f() { cout << "Derive::f" << endl; }
            virtual void g1() { cout << "Derive::g1" << endl; }
            virtual void h1() { cout << "Derive::h1" << endl; }

};

其中派生类重写了基类中的f()函数,派生类的虚函数表为
这里写图片描述

注意:
1)覆盖的派生类f()函数被放到了虚表中原来基类虚函数的位置
2)没有被覆盖的函数不变

(3)多重继承(无虚函数覆盖)
继承关系
这里写图片描述

子类的虚函数表为:
这里写图片描述

注意:
1) 每个基类都有自己的虚表。
2) 派生类的成员函数被放到了第一个基类的表中。(所谓的第一个父类是按照声明顺序来判断的)

(4)多重继承(有虚函数覆盖)
子类中覆盖了父类的f()函数
这里写图片描述

子类的虚函数表:
这里写图片描述

注意:
三个父类虚函数表中的f()的位置被替换成了子类的函数指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值