zoukankan      html  css  js  c++  java
  • 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++没有接口功能,那么这个纯虚函数便是用作接口功能
    • 底下的派生类只有将所有纯虚函数全部实现才能称之为_具体类_
    • 也可以用另一种观点来看,就是为所有派生类定义了规范
    • 这是一种面向接口的设计方式,也是面向抽象类的设计
    • 抽象类的设计需要非常谨慎,因为派生类需要围绕抽象类进行设计
    • 那么如果没有设计好抽象类,那么容易带偏派生类
    几个小规定
    • 抽象类只能用作基类
    • 不能声明抽象类的对象
      • 原因:抽象类中具有纯虚函数,而这个函数按语法可调用,但是这个函数没有实现,因而为了解决这个问题直接禁止了抽象类的声明
    • 构造函数不能够是虚函数,析构函数可以是虚函数
    • 可以定义抽象类的指针
  • 相关阅读:
    《AngularJS》5个实例详解Directive(指令)机制
    angularjs入门学习【指令篇】
    --@angularJS--综合小实例1
    --@angularJS--angular与BootStrap3的应用
    --@angularJS--ng-show应用
    --@angularJS--浅谈class与Ng-Class的应用
    --@angularJS--路由插件UI-Router
    --@angularJS--路由、模块、依赖注入
    Bootstrap兼容IE8
    ANGULAR JS PROMISE使用
  • 原文地址:https://www.cnblogs.com/Phoenix-blog/p/9073823.html
Copyright © 2011-2022 走看看