精华内容
下载资源
问答
  • override在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。...

    override在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法。

    1.公有继承


    包含两部分:一是“接口”(interface),二是 “实现” (implementation)。

    class Shape {
    public:
        virtual void Draw() const = 0;    // 1) 纯虚函数
        virtual void Error(const string& msg);  // 2) 普通虚函数
        int ObjectID() const;  // 3) 非虚函数
    };
    
    class Rectangle: public Shape { ... };
    class Ellipse: public Shape { ... };
    

    1. 1 纯虚函数

    纯虚函数,继承的是基类成员函数的接口,必须在派生类中重写该函数的实现:

    Shape *ps1 = new Rectangle;
    ps1->Draw(); // calls Rectangle::Draw
    
    Shape *ps2 = new Ellipse;
    ps2->Draw(); // calls Ellipse::Draw
    

    调用基类的 Draw(),须加 类作用域操作符 ::

    ps1->Shape::Draw(); // calls Shape::draw
    

    1.2 普通虚函数

    普通虚函数,对应在基类中定义一个缺省的实现 (default implementation),表示继承的是基类成员函数的接口和缺省的实现,由派生类自行选择是否重写该函数

    实际上,允许普通虚函数同时继承接口和缺省实现是危险的。 如下, CarA 和 CarB 是 Car的两种类型,且二者的运行方式完全相同

    class Car{ 
    public: 
     virtual void Run(const Car& destination); 
    }; 
    class CarA: public Car{ ... }; 
    class CarB: public Car{ ... };
    

    这是典型的面向对象设计,两个类共享一个特性 – Run,则 Run可在基类中实现,并由两个派生类继承。

    现增加一个新的飞机型号 CarC,其飞行方式与 CarA,CarB 并不相同,假如不小心忘了在 CarC 中重写新的 Fly 函数

    class CarC: public Car{ 
     ... // no fly function is declared 
    };
    

    这就是前面所说的,普通虚函数同时继承接口和缺省实现是危险的,最好是基类中实现缺省行为 (behavior),但只有在派生类要求时才提供该缺省行为.

    1. 方法一:

    一种方法是纯虚函数 + 缺省实现,因为是纯虚函数,所以只有接口被继承,其缺省的实现不会被继承。派生类要想使用该缺省的实现,必须显式的调用:

    class Car{ 
    public: 
     virtual void Run(const Run& destination) = 0; 
    }; 
      
    void Car::Run(const Airport& destination) 
    { 
     // a pure virtual function default code for Run an Car to the given destination 
    } 
      
    class CarA: public Car{ 
    public: 
     virtual void Run(const Car& destination) { Car::Run(destination); } 
    

    这样在派生类 CarC 中,即使一不小心忘记重写 Run函数,也不会调用 Car的缺省实现

    class CarC: public CAr{ 
    public: 
     virtual void Run(const Car& destination); 
    }; 
      
    void CarC::Run(const Car& destination) 
    { 
     // code for Run a CarC Car to the given destination 
    }
    

    2. 方法二:

    可以看到,上面问题的关键就在于,一不小心在派生类 CarC中忘记重写 Run函数,C++11 中使用关键字 override,可以避免这样的“一不小心”。
    非虚函数:

    非虚成员函数没有virtual关键字,表示派生类不但继承了接口,而且继承了一个强制实现(mandatory implementation),既然继承了一个强制的实现,则在派生类中,无须重新定义继承自基类的成员函数,如下:

    使用指针调用 Name 函数,则都是调用的 Person::Name()

    Student s1; // s1 is an object of type Student 
      
    Person *p= &s1; // get pointer to s1 
    p->Name(); // call Name() through pointer 
      
    Student *s= &s1; // get pointer to s1 
    s->Name(); // call Name() through pointer
    

    如果在派生类中重新定义了继承自基类的成员函数 Name

    class Student : public Person{ 
    public: 
     int Name() const; // hides Person::Name 
    }; 
      
    p->Name(); // calls Person::Name() 
    s->Name(); // calls Student::Name() 
    

    此时,派生类中重新定义的成员函数会 “隐藏” (hide) 继承自基类的成员函数

    这是因为非虚函数是 “静态绑定” 的,p被声明的是 Person* 类型的指针,则通过 p调用的非虚函数都是基类中的,既使 p指向的是派生类。

    与“静态绑定”相对的是虚函数的“动态绑定”,即无论 p被声明为 Person* 还是 Student* 类型,其调用的虚函数取决于 p实际指向的对象类型

    2 重写 (override)
    在程序中加override 关键字,可以避免派生类中忘记重写虚函数的错误

    下面以 Base 基类和 Derived 派生类为例,详细阐述之

    class Base { 
    public: 
     virtual void fun1() const; 
     virtual void fun2(int x); 
     virtual void fun3() &; 
     void fun4() const; // is not declared virtual in Base 
    }; 
      
    class Derived: public Base { 
    public: 
     virtual void fun1();  // declared const in Base, but not in Derived. 
     virtual void fun2(unsigned int x); // takes an int in Base, but an unsigned int in Derived 
     virtual void fun3() &&; // is lvalue-qualified in Base, but rvalue-qualified in Derived. 
     void fun4() const;   
    }; 
    

    在派生类中,重写 (override) 继承自基类成员函数的实现 (implementation) 时,要满足如下条件:

    一虚:基类中,成员函数声明为虚拟的 (virtual)

    二容:基类和派生类中,成员函数的返回类型和异常规格 (exception specification) 必须兼容

    四同:基类和派生类中,成员函数名、形参类型、常量属性 (constness) 和 引用限定符 (reference qualifier) 必须完全相同

    如此多的限制条件,导致了虚函数重写如上述代码,极容易因为一个不小心而出错

    C++11 中的 override 关键字,可以显式的在派生类中声明,哪些成员函数需要被重写,如果没被重写,则编译器会报错。

    class Derived: public Base { 
    public: 
     virtual void fun1() override; 
     virtual void fun2(unsigned int x) override; 
     virtual void fun3() && override; 
     virtual void fun4() const override; 
    };
    class Derived: public Base { 
    public: 
     virtual void fun1() const override; // adding "virtual" is OK, but not necessary 
     virtual void fun2(int x) override; 
     void fun3() & override; 
     void fun4() const override; 
    };
    

    1) 公有继承

    纯虚函数 => 继承的是:接口 (interface)
    普通虚函数 => 继承的是:接口 + 缺省实现 (default implementation)
    非虚成员函数 =>继承的是:接口 + 强制实现 (mandatory implementation)
    2) 不要重新定义一个继承自基类的非虚函数 (never redefine an inherited non-virtual function
    3)在声明需要重写的函数后,加关键字 override
    这样,即使不小心漏写了虚函数重写的某个苛刻条件,也可以通过编译器的报错,快速改正错误。

    在使用中需要注意以下几点:

    覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
    覆盖的方法的返回值必须和被覆盖的方法的返回一致;
    覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
    被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
     


    ————————————————
    版权声明:本文为CSDN博主「渐无书xh」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_42905141/article/details/94405090

    展开全文
  • C++新特性 虚函数override及类的final等

    千次阅读 2021-02-26 22:18:41
    待补充

    待补充

    //虚函数  override final default delete 在C++11新增
    struct Base
    {
    public:
    	virtual void foo() final {};//标注final
    
    };
    
    //子类继承父类函数重载
    class SubClass final :public Base
    {
    public:
    	// override显示的告诉这个是虚函数,在后期维护的时候可以方便看到,用于提醒  
    	void foo() override{};//b报错
    };
    
    // final 如果在类后面标注告诉编译器,这是最后一个类,无法在被继承的类
    //final 在虚函数后面,告诉派生类无法在重载这个类的虚函数了
    class subclass2 :public SubClass   //报错
    {
    public:
    };
    //default
    class Base01
    {
    public:
    	Base01() = default;//保留默认构造析构拷贝函数
    	Base01(int i)  //如何没有default 则默认没有无参构造
    	{
    	
    	}
    };
    //delete
    class Base02
    {
    public:
    	Base02() = delete;//禁止编译器参数默认构造
    	Base02(int i)  
    	{
    
    	}
    };
    int main()
    {
    	return 0;
    }

     

    展开全文
  • 一:基类指针与子类指针 在这里插入代码片 二:虚函数 ...c++11引入的override与final关键字在虚函数中的应用。 说明:override只能在子类中使用,而final只能在父类中使用,并且是只能用在虚函数上。 ...

    一:基类指针与子类指针

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class human
    {
    public:
    	void eat() { cout << "各种粮食" << endl; };
    };
    
    class man :public human
    {
    public:
    	void eat() { cout << "面食" << endl; };
    };
    
    class woman :public human
    {
    public:
    	void eat() { cout << "米饭" << endl; };
    };
    int main()
    {
    	//没问题,
    	human *phuman = new human; //基类指针
    	man   *pman = new man; //子类指针
    	woman *pwoman = new woman; //子类指针
    
    
    	//新玩法,一个父类指针可以new一个子类对象
    	human *phuman1 = new man; 
    	phuman1->eat();//虽然是new子类对象,但是,这里调用的还是父类中的eat函数。
    
    	/*
    	说明:
    	1:一个父类指针可以new一个对象,是因为子类中含有的子对象包括父类,
    		但是,一个子类new一个父类对象就不可以了。
    	2:我要怎么样用一个父类指针就可以调用子类中的eat函数呢?
    	*/
    	
    	return 0;
    }
    

    二:虚函数

    /*一:抛出了一个问题,即如何用一个父类指针去调用子类里的eat函数?有办法吗?有,那就是引入虚函数,这样就可以用一个父类指针即调用父类的eat函数又可以调用子类的eat函数了*/
    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class human
    {
    public:
    	virtual void eat() { cout << "各种粮食" << endl; };
    	/*
    	在函数声明前加上virtual,这个函数就成了虚函数了,注意是声明,不是定义,
    	要是声明和定义放在一块,也可以加上virtual,就像上面那样。
    	在类外实现时,不用加virtual
    	*/
    };
    
    class man :public human
    {
    public:
    	void eat() { cout << "面食" << endl; };
    };
    
    class woman :public human
    {
    public:
    	void eat() { cout << "米饭" << endl; };
    };
    int main()
    {
    	human *phuman = new man;
    	phuman->eat(); //这样调用的就是子类的eat函数了
    
    	//那我怎么调用父类里的eat函数?
    	human *phuman1 = new man;
    	phuman1->human::eat();//ok,显示调用的父类的eat函数	
    	/*
    		eat函数。如果在类中中加了virtual,那么子类中就不用加上这个关键字了
    		这样,在调用eat函数的时候,执行的就是动态绑定了,即new什么就调用谁
    	*/
    	return 0;
    }
    

    三:override与final关键字
    c++11引入的override与final关键字在虚函数中的应用。

    说明:override只能在子类中使用,而final只能在父类中使用,并且是只能用在虚函数上(或者是用在基类上,用来阻止派生类的继承)。

    final与override相对,在父类的虚函数加上它以后,就是说,不要希望在子类中去覆盖父类的eat函数,用了final以后,再用override就不可以了。或者说是用了final以后,子类中就不能在写eat函数了。

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class human
    {
    public:
    	virtual void eat() { cout << "各种粮食" << endl; };
    	/*
    	在函数声明前加上virtual,这个函数就成了虚函数了,注意是声明,不是定义,
    	要是声明和定义放在一块,也可以加上virtual,就像上面那样。
    	在类外实现时,不用加virtual
    	*/
    
    	/*
     virtual void eat() final; 这样写,后面子类就不能写eat函数了。
       */
    };
    
    class man :public human
    {
    public:
    	void eat() { cout << "面食" << endl; };
    };
    
    class woman :public human
    {
    public:
    	void eat(int a) override{ cout << "米饭" << endl; }; /*错误,加上override的意思是说,要覆盖父类中的同名同参的虚函数函数,也就是说,为了防止我们写错参数个数或者函数名,那么你加上override以后,编译器就会对你提示错误,比如这里报错的原因就是因为,父类的虚函数中,没有参数为int的eat函数*/
    };
    int main()
    {
    	human *phuman = new man;
    	phuman->eat(); //这样调用的就是子类的eat函数了
    
    	//那我怎么调用父类里的eat函数?
    	human *phuman1 = new man;
    	phuman1->human::eat();//ok,显示调用的父类的eat函数	
    	/*
    		eat函数。如果在类中中加了virtual,那么子类中就不用加上这个关键字了
    		这样,在调用eat函数的时候,执行的就是动态绑定了,即new什么就调用谁
    	*/
    	return 0;
    }
    
    

    附:有那些函数不能声明为虚函数:
    https://www.cnblogs.com/dingou/p/11627596.html

    展开全文
  • C++ 虚函数看这一篇 目的是用一个指针,既能调用父类的函数,又能调用子类的函数(同名同参同返回值(返回值可以有点小差别,不是相互转换类型))。 这个对象指针,它的类型必须是父类类型。 父类成员函数必须声明...

    C++ 虚函数看这一篇


    目的是用一个指针,既能调用父类的函数,又能调用子类的函数(同名同参同返回值(返回值可以有点小差别,不是相互转换类型))。
    这个对象指针,它的类型必须是父类类型。
    父类成员函数必须声明之前加virtual,声明成虚函数,定义时不加。子类中加不加都行,最好加,方便阅读。
    一旦某个函数(基类)被声明成了虚函数,在所有派生类(子类)中都是虚函数,子类的虚函数与父类一样。如果父类子类形参不同,则是两个完全不同的函数,子类函数与父类函数无关。

    class Human {
    public:
    	//声明成虚函数
    	virtual  void eat() ;
    };//类结尾一定要分号
    
    class Man : public Human //表示Men是Humen的子类
    {
    public:
    	virtual void eat() ;
    };//类结尾一定要分号
    
    int main() {
    	Human* phuman = new Man();
    	phuman->eat();//调用子类的eat(),如果子类没有,调用父类的
    	delete phuman;
    	phuman = new Human();
    	phuman->ean();//调用父类的eat()。
    	return 0;
    }
    

    如果还想调用父类的虚函数,可以

    phuman->Human::eat();//调用父类的函数。
    

    为了避免写错虚函数,c++11可以在函数声明处增加一个override关键字。这个关键字用在子类中,而且是虚函数专用。
    overide 就是用来说明派生列的虚函数。用了这个关键字,编译器会认为子类函数覆盖了父类的同名函数。只有虚函数才存在子类覆盖父类同名函数的现象。编译器会在父类中找同名同参的虚函数,如果没找到,编译器会报错。可以防止在子类中写错虚函数名字,参数等问题,编译器能够纠错。

    class Man : public Human //表示Men是Humen的子类
    {
    
    public:
    	virtual void eat() override ;//纠错用的
    };
    

    final也是虚函数专用,用在基类中。如果在父类函数声明中,如果加了final任何尝试覆盖该函数的操作都将引发错误。final必须用在虚函数。

    virtual void eat() final;
    

    虚函数必须写定义部分。
    调用虚函数执行的是动态绑定
    动态:在程序运行时,才知道调用了哪个子类的虚函数。绑定到哪里取决于new的东西。
    动态绑定:运行时才决定指针指向的对象绑定到哪个成员函数上运行。

    只能用指针来调用虚函数,普通的对象不行

    Men men;
    mem.eat()//调用men的函数
    
    展开全文
  • C++多态--虚函数virtual及override

    万次阅读 多人点赞 2017-08-16 23:35:52
    C++多态(polymorphism)是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。 最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,...
  • 公有继承包含两部分:一是 “函数接口” (interface),二是 “函数实现” (implementation) 如 Shape 类中,三个成员函数,对应三种继承方式: class Shape { public: virtual void Draw() const = 0; // 1) 纯虚...
  • 初识虚函数 用virtual关键字说明的函数; 虚函数是实现运行时多态性基础; C++中的虚函数是动态绑定的函数; 虚函数必须是非静态的成员函数,虚函数经过派生之后,就可以实现运行过程中的多态; 一般成员函数可以...
  • C++11新特性之虚函数override指示符

    千次阅读 2017-09-03 23:24:53
    2. 下面Demo中,Student类继承于People类(public公有继承),在People类中对PrintInf函数进行了虚函数的声明;为了实现多态(多态的3个条件:有继承、虚函数重写(覆盖)、有父类指针或引用指向子类对象);在父类...
  • 3. 重载函数的调用是以所传递参数的差别作为调用不同函数的依据,虚函数是根据对象动态类型的不同去调用不同的类的虚函数; 4. 重载函数在编译时表现出多态性,而虚函数在运行时便显出多态功能。
  • 【c++】虚函数描述符override

    千次阅读 2014-05-10 12:45:25
    C++11中为了帮助程序员写继承结构复杂的类型,引入了虚函数描述符override 重载虚函数 就加上关键字override 这样编译器可以辅助检查是不是正确重载,如果没加这个关键字 也没什么严重的error 只是少了编译器检查的...
  • 在传统C++中,经常容易发现意外重载虚函数的事情: struct Base { virtual void foo(); }; struct SubClass: Base { void foo(); }; 有下列三种场景: SubClass::foo可能是程序员加入的一个和基类虚函数恰好...
  • C++笔记 15.2 虚函数

    2020-09-05 19:53:17
    primer C++笔记 虚函数 派生类中的虚函数 override final 虚函数与默认实参 回避虚函数的机制
  • #include<iostream> using namespace std;...//对于虚函数 final 当前虚函数到此为止,子类不能对这个虚函数进行重写。 class Base { public: virtual void foo() final {} ; Base(int n) { /...
  • override确保在派生类中声明的重载函数跟基类的虚函数有相同的签名。final阻止类的进一步派生和虚函数的进一步重载。接下来让我们看看这些监督者如何消除你在类层次结构的设计和实施中的bug吧。 虚函数重载 ...
  • 5.显示虚函数重载 在 C++ 里,在子类中容易意外的重载虚函数。举例来说: struct Base { virtual void some_func(); }; struct Derived : Base { void some_func(); }; Derived::some_func 的真实意图为何? ...
  • 在C++11中为了帮助程序猿写继承结构复杂的类型,引入了虚函数描写叙述符override,假设派生类在虚函数声明时使用了override描写叙述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译。我们来看...
  • override:对虚函数进行重写的函数 final与override 假设声明一个基类的指针,它可以根据指向的对象类型动态的绑定对应的函数 虚函数的默认实参 如果我们通过基类的引用或指针调用函数,则使用基类中定义的默认实参 ...
  • override 仅在成员函数声明之后使用时才是区分上下文的且具有特殊含义;否则,它不是保留的关键字。使用 override 有助于防止代码中出现意外的继承行为。以下示例演示在未使用override 的情况下,可能不打算使用派生...
  • c# 虚函数Virtual与重写override

    千次阅读 2016-04-26 11:45:37
    C#代码 using System; namespace Smz.Test { class A { public virtual void Func() // 注意virtual,表明这是一个虚拟函数 { Console.
  • class Program { static void Main() { B b = new B(); ... public override void PrintFields() ...调试的时候发现运行类A 构造函数A()时 调用 PrintFields()...确会去运行类B的 public override void PrintFields()
  • virtual 函数类型 函数名称(参数列表)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,002
精华内容 14,400
关键字:

虚函数override