0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C/C++之面向对象编程思想3

jf_78858299 来源:小余的自习室 作者:小余的自习室 2023-03-30 15:16 次阅读

运算符重载函数

运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,简化操作 让已有的运算符 适应不同的数据类型

  • 格式:
    重载+=号运算 ==>operator+=
    重载+运算符 ==>operator+ 
    ...
    

下面举两个运算符重载例子:

  • 1.重载+号
    class Complex {
      public:
        Complex() {
    
        }
        double real, imag;
        Complex(double _real, double _imag):
            real(_real),imag(_imag)
        {
            cout << "real:" << real << " imag:" << imag << endl;
        }
        void print() {
            cout << "real:" << real << " imag:" << imag << endl;
        }
        Complex(const Complex& c) {
            real = c.real; imag = c.imag;
            cout << "complex copy" << endl;
        }
        //以全局函数的形式重载
        friend Complex operator+(const Complex& c1, const Complex& c2);
    
    };
    Complex operator+(const Complex& c1, const Complex& c2) {
        Complex _c;
        _c.real = c1.real + c2.real;
        _c.imag = c1.imag + c2.imag;
        return _c;
    }
    Complex func() {
        Complex c(1.0, 2.0);
        Complex c1(2.0, 3.0);
        Complex c2 = c + c1;
        return c2;
    }
    
    void extendsTest::mainTest()
    {   
        cout << func().real << endl;
    };
    运行结果:
    real:1 imag:2
    real:2 imag:3
    complex copy
    complex copy
    3
    
  • 2.重载+=号运算 代码如下:
    class Complex {
      public:
        ...
        //成员函数重载
        Complex& operator+=(const Complex& c);
      };
    
    Complex & Complex::operator+=(const Complex& c1) {
        this->real += c1.real;
        this->imag += c1.imag;
        return *this;
    }
    Complex func() {
        Complex c(1.0, 2.0);
        Complex c1(2.0, 3.0);
        c += c1;
        return c;
    }
    void extendsTest::mainTest()
    {   
        cout << func().real << endl;
    };
    运行结果:
    real:1 imag:2
    real:2 imag:3
    complex copy
    3
    
运算符重载的限制

多数C++运算符都可以重载,重载的运算符不必是成员函数,但必须至少有一个操作数是用户定义的类型。

    1. 重载后的运算符必须至少有一个操作数是用户定义的类型 ,防止用户为标准类型重载运算符。如:不能将减法运算符(-)重载为计算两个 double 值的和,而不是它们的差。虽然这种限制将对创造性有所影响,但可以确保程序正常运行。
    1. 使用运算符时不能违反运算符原来的句法规则 。例如,不能将求模运算符(%)重载成使用一个操作数:int x;Time shiva;%x;%shiva;,且不能修改运算符的优先级。
    1. 不能创建新运算符 。例如,不能定义operator **()函数来表示求幂。
  • 4.不能重载下面的运算符。

    图片

运算符重载涉及的知识点还是比较多的,后期文章会单独出一期讲解。

多态

多态是指:函数调用的多种形态,使用多态可以使得不同的对象去完成同一件事时,产生不同的动作和结果

C++中多态分为 静态多态和动态多态

静态多态

静态多态的核心思想对于相关的对象类型,直接实现他们各自的定义,不需要共有基类,甚至可以没任何关系, 只需要各个具体类的实现中要求相同的接口声明,这里的接口称之为隐式接口。客户端把操作这些对象的函数定义为模板,当需要操作什么类型的对象时,直接对模板指定该类型实参即可(或通过实参演绎获得)

在模板编程及泛型编程中,是以隐式接口和编译器多态来实现静态多态。

代码如下:

class Circle {
public:
    void Draw() const{
        cout << "Circle draw" << endl;
    }
    int z;
};
class Rectangle {
public:
    void Draw() const{
        cout << "Rectangle draw" << endl;
    }
};
template<typename T>
void test(const T& t) {
    t.Draw();
}
void extendsTest::mainTest()
{   
    //cout << func().real << endl;
    Circle cir;
    test(cir);
    Rectangle rec;
    test(rec);
};

打印结果:
Circle draw
Rectangle draw

静态多态本质上就是模板的具现化, 静态多态中的接口调用也叫做隐式接口 ,相对于显示接口由函数的签名式(也就是函数名称、参数类型、返回类型)构成,隐式接口通常由有效表达式组成

动态多态

动态多态核心思想对于相关的对象类型,确定它们之间的一个共同功能集,然后在基类中, 把这些共同的功能声明为多个公共的虚函数接口。各个子类重写这些虚函数, 以完成具体的功能。客户端的代码(操作函数)通过指向基类的引用或指针来操作这些对象, 对虚函数的调用会自动绑定到实际提供的子类对象上去。

动态多态是在运行期完成的,这造就了动态多态机制在处理异质对象集合时的强大威力(当然,也有了一点点性能损失)。

如下代码:

class Geometry {
public:
    virtual void Draw() const=0;
};
class Circle :public Geometry{
public:
    void Draw() const{
        cout << "Circle draw" << endl;
    }
    int z;
};
class Rectangle :public Geometry {
public:
    void Draw() const{
        cout << "Rectangle draw" << endl;
    }
};
void extendsTest::mainTest()
{   
    Circle cir;
    const Geometry* e1 = ○
    e1->Draw();
    Rectangle rec;
    const Geometry* e2 = &rec;
    e2->Draw();

};
打印结果:
Circle draw
Rectangle draw

//动态多态最吸引人之处在于处理异质对象集合的能力

void DrawVec(std::vector
    {
        const size_t size = vecGeo.size();
        for(size_t i = 0; i < size; ++i)
            vecGeo[i]->Draw();
    }
}

动态多态本质上就是面向对象设计中的继承、多态的概念。动态多态中的接口是显式接口(虚函数)

动态多态构成条件

  • 1.必须通过基类的指针或者引用调用虚函数。
  • 2.被调用的函数必须是虚函数,且子类必须对父类的虚函数进行重写。

动态多态实现原理:虚函数表

class Geometry {
public:
    virtual void Draw() const=0;
};
class Circle :public Geometry{
public:
    void Draw() const{
        cout << "Circle draw" << endl;
    }
    int z;
};
class Rectangle :public Geometry {
public:
    void Draw() const{
        cout << "Rectangle draw" << endl;
    }
};
void extendsTest::mainTest()
{   
    Circle cir;
    const Geometry* e1 = ○
    e1->Draw();

};

Circle对象中除了z成员变量外,实际上还有一个指针_vfptr放在对象的前面(有些平台可能会放到对象的最后面,这个跟平台有关).

图片

对象中的这个指针叫做虚函数表指针,简称虚表指针,虚表指针指向一个虚函数表,简称虚表,每一个含有虚函数的类中都至少有一个虚表指针。

#include 
using namespace std;
//父类
class Base
{
public:
    //虚函数
    virtual void Func1()
    {
        cout << "Base::Func1()" << endl;
    }
    //虚函数
    virtual void Func2()
    {
        cout << "Base::Func2()" << endl;
    }
    //普通成员函数
    void Func3()
    {
        cout << "Base::Func3()" << endl;
    }
private:
    int _b = 1;
};
//子类
class Derive : public Base
{
public:
    //重写虚函数Func1
    virtual void Func1()
    {
        cout << "Derive::Func1()" << endl;
    }
private:
    int _d = 2;
};
int main()
{
    Base b;
    Derive d;
    return 0;
}

图片

虚表当中存储的就是虚函数的地址,因为父类当中的Func1和Func2都是虚函数,所以父类对象b的虚表当中存储的就是虚函数Func1和Func2的地址。而子类虽然继承了父类的虚函数Func1和Func2,但是子类对父类的虚函数Func1进行了重写,因此,子类对象d的虚表当中存储的是父类的虚函数Func2的地址和重写的Func1的地址。

这就是为什么虚函数的重写也叫做覆盖,覆盖就是指虚表中虚函数地址的覆盖,重写是语法的叫法,覆盖是原理层的叫法。

虚函数表本质是一个存虚函数指针的指针数组,一般情况下会在这个数组最后放一个nullptr。

当满足多态条件以后,父类的指针或引用调用虚函数时,不是编译时确定的,而是运行时到指向的对象中的虚表中去找对应的虚函数调用,并且引用的底层也是由指针实现,父类在指向子类时会发生切片。 所以指针指向父类的对象,调用的就是父类的虚函数,指向的是子类对象,调用的就是子类的虚函数。

动态多态和静态多态的比较

静态多态优点:

静态多态是在编译期完成,因此效率高,编译器可以进行优化。 有很强的是适配性和松耦合性。 最重要一点 通过模板编程为C++带来了泛型设计的概念 ,比如强大的STL库

静态多态缺点:

由于是模板来实现静态多态,因此 模板的不足也就是静多态的劣势 ,比如调试困难、编译耗时、代码膨胀、编译器支持的兼容性,不能够处理异质对象集合。

动态多态优点:

OO设计,对是客观世界的直觉认识;

实现与接口分离,可复用;

处理同一继承体系下异质对象集合的强大威力

动态多态缺点:

运行期绑定,导致一定程度的运行时开销

编译器无法对虚函数进行优化;

笨重的类继承体系,对接口的修改影响整个类层次;

不同点:

本质不同,静态多态在编译期决定,由模板具现完成,而动态多态在运行期决定,由继承、虚函数实现;

动态多态中接口是显式的,以函数签名为中心,多态通过虚函数在运行期实现,静态多台中接口是隐式的,以有效表达式为中心,多态通过模板具现在编译期完成。

相同点:

都能够实现多态性,静态多态/编译期多态、动态多态/运行期多态;

都能够使接口和实现相分离,一个是模板定义接口,类型参数定义实现,一个是基类虚函数定义接口,继承类负责实现;

总结

本篇文章详解讲解了C++中的面向对象编程的三大特性:封装,继承以及多态 以及对象编程中模板编程,虚函数,构造函数,析构函数,拷贝构造,操作符重载等知识 , 知识点还是比较多的,需要好好消化下。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2957

    浏览量

    104534
  • C++
    C++
    +关注

    关注

    22

    文章

    2104

    浏览量

    73482
  • 面向对象编程

    关注

    0

    文章

    22

    浏览量

    1805
收藏 人收藏

    评论

    相关推荐

    Labview 之面向对象编程。 里面有个例子 和视频教程地址

    Labview 之面向对象编程。 里面有个例子 和视频教程地址Labview 之面向对象编程
    发表于 12-29 10:16

    C++ 面向对象多线程编程下载

    C++ 面向对象多线程编程下载
    发表于 04-08 02:14 70次下载

    C++面向对象多线程编程 (pdf电子版)

    C++面向对象多线程编程共分13章,全面讲解构建多线程架构与增量多线程编程技术。第1章介绍了
    发表于 09-25 09:39 0次下载

    C++课件

     C++面向对象程序设计 面向对象思想的由来面向
    发表于 04-10 13:41 0次下载

    Visual C++面向对象与可视化程序设计习题解析与编程

    Visual C++面向对象与可视化程序设计习题解析与编程实例从最基本的概念出发,详细地讲述了使用Visual C++进行
    发表于 07-12 15:16 0次下载
    Visual <b class='flag-5'>C++</b><b class='flag-5'>面向</b><b class='flag-5'>对象</b>与可视化程序设计习题解析与<b class='flag-5'>编程</b>实

    C++编程思想

    C++编程思想,很好的资料,大家下载看看吧!够20字了吧,哈哈哈!
    发表于 11-17 11:38 0次下载

    面向对象的程序设计(C++

    面向对象的程序设计(C++).面向对象的基本思想 C++
    发表于 03-22 14:40 0次下载

    C#入门教程之面向对象编程简介的详细资料概述

    本文档的主要内容详细介绍的是C#入门教程之面向对象编程简介的详细资料概述主要学习的目标是1.面向对象
    发表于 12-05 11:54 35次下载
    <b class='flag-5'>C</b>#入门教程<b class='flag-5'>之面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>简介的详细资料概述

    C++语言和面向对象程序设计教程

    章至第11章介绍符合C++国际标准的C++面向对象程序设计思想和方法;第12章和第13章分别介绍面向
    发表于 03-02 08:00 6次下载

    STM32 C++编程系列二:STM32 C++代码封装初探

    一、STM32与面向对象编程上一章中提到了,C++的核心之一就在于面向对象
    发表于 12-08 11:06 13次下载
    STM32 <b class='flag-5'>C++</b><b class='flag-5'>编程</b>系列二:STM32 <b class='flag-5'>C++</b>代码封装初探

    嵌入式C语言面向对象编程应用及优势

    既然面向对象是一种编程思想,而编程语言只是一种工具,那么,思想与工具之间就不存在一种强耦合的关系
    发表于 11-10 12:00 1721次阅读
    嵌入式<b class='flag-5'>C</b>语言<b class='flag-5'>面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>应用及优势

    C语言是怎么面向对象编程

    在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向
    的头像 发表于 02-14 13:57 1628次阅读
    <b class='flag-5'>C</b>语言是怎么<b class='flag-5'>面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b>

    C/C++之面向对象编程思想1

    C++作为一门在C和Java之间的语言,其既可以使用C语言中的高效指针,又继承了Java中的面向对象编程
    的头像 发表于 03-30 15:14 619次阅读
    <b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>之面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b><b class='flag-5'>思想</b>1

    C/C++之面向对象编程思想2

    C++作为一门在C和Java之间的语言,其既可以使用C语言中的高效指针,又继承了Java中的面向对象编程
    的头像 发表于 03-30 15:14 554次阅读
    <b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>之面向</b><b class='flag-5'>对象</b><b class='flag-5'>编程</b><b class='flag-5'>思想</b>2

    浅谈C语言面向对象编程思想

    C语言是一种面向过程的语言,但是也可以用结构体和函数指针来模拟面向对象的特性,比如封装、继承和多态。
    发表于 11-02 12:27 1026次阅读