日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++中Covariant返回值類型詳解_C 語言

作者:ithiker ? 更新時間: 2022-11-03 編程語言

前言

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,失去了動態綁定的意義。

原文鏈接:https://blog.csdn.net/ithiker/article/details/109013385

欄目分類
最近更新