C++中Covariant返回值类型详解

 更新时间:2022年09月09日 10:55:49   作者:ithiker  
这篇文章主要介绍了C++中Covariant返回值类型详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以可以参考一下

前言

C++中当子类覆写(override)父类虚函数时,子类函数的返回值类型可以和父类函数的返回值类型不一致吗?
先说结论:可以,但当且仅当它们的返回值类型是协变返回值类型(Covariant)时可以。C++中gcc从3.4开始支持这一特性。

什么是协变返回值类型(Covariant)

函数的协变返回值类型指的是子类中的成员函数的返回值类型不必严格等同与该函数所重写的父类中的函数的返回值类型,而可以是更 “狭窄” 的类型。C++/Java等面向对象编程语言均支持协变返回值类型。

例子:

class Shape {
public:
  virtual ~Shape() { }          
  virtual Shape* clone()  const = 0;   // Uses the copy constructor
  virtual Shape* create() const = 0;   // Uses the default constructor
};
class Circle : public Shape {
public:
  Circle* clone()  const;   // Covariant Return Types; see below
  Circle* create() const;   // Covariant Return Types; see below
 
};
Circle* Circle::clone()  const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle();      }

C++中不支持virtual constructor,因为:

  • 创建对象时需要知道对象的完整信息
  • 虚函数机制也决定了对象尚未创建时,类的virtual table或许还不存在
  • 我们不可能有指向virtual constructor的指针

但是我们可以通过上面的代码实现类似的想法,如果我们拥有指向对象的指针:

  • 通过clone()调用对象的拷贝构造函数,复制当前的对象
  • 通过create()调用默认构造函数,创建新的对象

比如下面的使用场景:

void userCode(Shape* s)
{
  Shape* s2 = s->clone();
  Shape* s3 = s->create();
  // ...
  delete s2;   
  delete s3;
}

如果指针指向的是基类对象,调用上述函数时返回的就是指向基类对象的指针并赋值给s2/s3,如果指针指向的是子类对象,调用上述函数时返回的就是指向子类对象的指针并赋值给s2/s3。

协变返回值类型(Covariant)的作用

协变返回类型到底有什么用呢,编译器为什么要支持这种语法?如果编译器不支持,上面的例子将只能写成如下这样:

class Shape {
public:
  virtual ~Shape() { }          
  virtual Shape* clone()  const = 0;   // Uses the copy constructor
  virtual Shape* create() const = 0;   // Uses the default constructor
};
class Circle : public Shape {
public:
  Shape* clone()  const;   // Covariant Return Types; see below
  Shape* create() const;   // Covariant Return Types; see below
 
};
Shape* Circle::clone()  const { return new Circle(*this); }
Shape* Circle::create() const { return new Circle();      }

这样上面的userCode函数将不能通过编译,上面调用clone函数部分将不得不改写成下面这样:

 void userCode(Shape* s)
{
  Shape* s2 = s->clone();
  Circle* c = dynamic_cast<Circle*>(s2);
  if (c != NULL) {
     // c point to Circle
  } else {
	  if (s2 != NULL) {
	     // s2 point to base Shape
	     }
	  }
  }
  // ...
  delete s2;   
}

通过if/else分支来判断s是指向子类Circle还是指向基类Shape,失去了动态绑定的意义。

到此这篇关于C++中Covariant返回值类型详解的文章就介绍到这了,更多相关C++ Covariant内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++跳转语句之Goto对变量定义的影响详解

    C++跳转语句之Goto对变量定义的影响详解

    goto语句也被称为无条件转移语句,这篇文章主要介绍了C++跳转语句之Goto对变量定义的影响,文中通过示例代码解文字介绍的很详细,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面跟着小编一起来学习学习吧。
    2016-11-11
  • 简单分析针对ARM平台的C语言程序的编译问题

    简单分析针对ARM平台的C语言程序的编译问题

    这篇文章主要介绍了针对ARM平台的C语言程序的编译问题,从优化编译选项的几个方面进行分析,需要的朋友可以参考下
    2015-12-12
  • 浅析C++中dynamic_cast和static_cast实例语法详解

    浅析C++中dynamic_cast和static_cast实例语法详解

    这篇文章主要介绍了浅析C++中dynamic_cast和static_cast实例演示,包括static_cast语法知识和static_cast的作用讲解,namic_cast 语法详解,需要的朋友可以参考下
    2021-07-07
  • 华为面试题答案找出最大长度子字符串

    华为面试题答案找出最大长度子字符串

    找出最大长度子字符串,打印并且返回长度。 例如 str = "abc123abcd234abcdefgha324adsdawqdasdaseqqwe345abchded",看下面的代码实现吧
    2013-12-12
  • C语言选择排序算法及实例代码

    C语言选择排序算法及实例代码

    本篇文章主要介绍了 C语言选择排序算法,这里提供代码实例以便大家理解,通过本文,更好的理解排序算法
    2016-07-07
  • C++实现LeetCode(557.翻转字符串中的单词之三)

    C++实现LeetCode(557.翻转字符串中的单词之三)

    这篇文章主要介绍了C++实现LeetCode(557.翻转字符串中的单词之三),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C语言数据结构中数制转换实例代码

    C语言数据结构中数制转换实例代码

    这篇文章主要介绍了C语言数据结构中数制转换实例代码的相关资料,需要的朋友可以参考下
    2017-03-03
  • 使用C++和代理IP实现天气预报的采集

    使用C++和代理IP实现天气预报的采集

    在当今的互联网时代,网络信息的获取变得日益重要,天气预报信息作为日常生活的重要参考,其获取方式也随着技术的发展而不断变化,在本文中,我们将探讨如何使用C++和代理IP来采集天气预报信息,文中通过代码讲解的非常详细,需要的朋友可以参考下
    2023-12-12
  • C/C++判断素数的三种方法

    C/C++判断素数的三种方法

    这篇文章主要给大家介绍了C/C++判断素数的三种方法,常规的函数判断法,埃氏筛法和欧拉筛法这三种方法,并通过代码示例讲解的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2023-12-12
  • C语言实现登录注册和忘记密码功能

    C语言实现登录注册和忘记密码功能

    这篇文章主要为大家详细介绍了C语言实现登录、注册和忘记密码功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12

最新评论