• c++运算符重载和虚函数


    运算符重载与虚函数

    单目运算符

    接下来都以AClass作为一个类例子介绍

    AClass{

    int var

    }

    • 区分后置++与前置++
    • AClass operator ++ () ++前置 一般设计为返回引用 这样的话可以将其作为左值(自然也可以作为右值,会调用该类的拷贝构造函数) ++class = ...
    • AClass operator ++ (int) 后置++ 一般设计返回一个旧的类 获得的是历史版本,所含有的int形参是用作区分类型的,并无实际含义
    • 由于一个__单变量__的构造函数可被视为__强制类型转换函数__
    多目运算符
    • AClass & operator (const & Aclass a){ ... }

    • 因此如果该类的构造函数满足把int变成这个类,你甚至可以这么写

    • int a; AClass A; A = A + a

    函数的默认形参值只能写在声明里,不能写在定义里

    • 对于<< 的重载方式,定义友元函数
    • frend ostream & operator << (ostream & out, const ...)
    • 这样ostream就能访问该类的私有成员了
    • 注意!插入运算符<< 的返回值要是这个out的引用
    • {... return & out} 这样就可以实现一直<<插入的神奇功能(请自己思考为什么, 提示:返回引用等于又把自己拿出来用了)

    虚函数

    覆盖 override 重载 overload

    虚函数基本语法

    巧妙的覆盖方式

    • 虚函数的声明
    • virtual 函数类型 函数名(形参表){
    • 函数内容}
    • 可以在基类中声明虚函数,则子类中的相关函数会被同样被认为为虚函数
    • 并且在创建基类指针指向一个子类时
    • 调用该基类指针的这个虚函数
    • 该指针会顺着找到子类的这个函数并且运行
    • 体现了程序运行过程中的__动态多态特性__
    • 例子
    class Base{
        virtual void func(){
            cout << "Base" << endl;
        }
    }
    class Base1{
        void func(){
            cout << "Base1" << endl;
        }
    }
    class Base2: public base{
        void func(){
            cout << "Base2" << endl;
        }
    }
    void display(base * ptr)
    int main(){
        Base1 b1;
        Base2 b2;
        Base * ptr1 = b1;
        Base * ptr2 = b2;
        display(ptr1);
        display(ptr2);
    }
    
    /*
    输出结果
    Base1
    Base2
    
    */
    

    typeid

    • typeid(ptr).name() 此处ptr为一个指针,返回这个指针的类型
    • typeid(* ptr).name() 此处返回的是ptr指向对象的类型
    • 如果你对上面的ptr1 ptr2进行第一种操作返回类型为base
    • 但是如果做第二种操作返回是base1和base2
    虚析构函数

    可能你想不到,析构函数也很虚

    • 析构函数和构造函数是不会继承的
    • 加上析构函数在组合关系中会按拓扑序反向调用
    • 那么要虚构函数的理由就是有时候你需要动态删除由__基类指针指向的派生类__
    • 没有虚函数你就只能把指针指向的东西__当成基类__,而其本身是__派生类__,进行了析构
    • 那么这样子你就会漏去除一些内容
    • 这样很不优雅(你可以想象内存会出现什么严重后果)
    举个栗子!
    • 比如我这么引用Base *b = new Derived()

    derived 代指派生类

    • 那么我们的b一调用delete就凉凉了
    • delete b
    • 编译器高兴地把b指向的地方当做Base删掉了
    • 仔细想想,Derived的构造函数被调用了,但是析构函数被忽略了,(原因是我换了一个指针引用)
    解决方法(就是虚析构函数)
    • 给基类的析构函数前面加个virtual关键字
    • 那么这就给这个东西加上了__动态多态性!__
    • 然后编译器就会跑去先调用一下Derived类的析构函数然后再调用Base的

    纯虚函数

    很纯洁的函数

    • 想想,概念都是完美的东西,那么纯虚函数就是用来描述概念的
    纯虚函数语法
    • virtual 类型 函数名(参数列表) = 0
    • 正如你所见,它没有函数体(非常的纯)
    • 带有纯虚函数的类称之为__抽象类__(另一个叫做__具体类__)
    抽象类
    概念及理念
    • 为啥需要抽象类
    • 由于c++没有接口功能,那么这个纯虚函数便是用作接口功能
    • 底下的派生类只有将所有纯虚函数全部实现才能称之为_具体类_
    • 也可以用另一种观点来看,就是为所有派生类定义了规范
    • 这是一种面向接口的设计方式,也是面向抽象类的设计
    • 抽象类的设计需要非常谨慎,因为派生类需要围绕抽象类进行设计
    • 那么如果没有设计好抽象类,那么容易带偏派生类
    几个小规定
    • 抽象类只能用作基类
    • 不能声明抽象类的对象
      • 原因:抽象类中具有纯虚函数,而这个函数按语法可调用,但是这个函数没有实现,因而为了解决这个问题直接禁止了抽象类的声明
    • 构造函数不能够是虚函数,析构函数可以是虚函数
    • 可以定义抽象类的指针
  • 相关阅读:
    Time Zone 【模拟时区转换】(HDU暑假2018多校第一场)
    HDU 1281 棋盘游戏 【二分图最大匹配】
    Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】
    Codeforces Round #527 (Div. 3) D2. Great Vova Wall (Version 2) 【思维】
    Codeforces Round #527 (Div. 3) D1. Great Vova Wall (Version 1) 【思维】
    Codeforces Round #528 (Div. 2, based on Technocup 2019 Elimination Round 4) C. Connect Three 【模拟】
    Avito Cool Challenge 2018 E. Missing Numbers 【枚举】
    Avito Cool Challenge 2018 C. Colorful Bricks 【排列组合】
    005 如何分析问题框架
    004 如何定义和澄清问题
  • 原文地址:https://www.cnblogs.com/Phoenix-blog/p/9073823.html
Copyright © 2020-2023  润新知