派生類向基類的可訪問性的第二條:派生類的成員函數能使用派生類到基類的轉換。

我理解,向基類轉換是為了滿足多態性,即基類指針調用派生類的函數。

但在派生類中,需要這樣的多態性嗎?


這個轉換的目的不是多態,而是函數復用,或是代碼復用。典型的例子是 private 繼承,代碼大概是下面這樣:

class Base {
public: void DoSomething();
};

class D1 : private Base {
void Foo1() { Base::DoSomething(); std::cout &

為了復用代碼,還有一種常見的範式是 Base 實現部分功能,但不允許直接構造析構,代碼大概是下面這樣:

class Base {
public:
void DoSomething(); // only use members in Base
protected:
void DoInternal();
Base() = default;
~Base() = default();
};

class D final : public Base {
public:
D() = default;
~D() = default;
void Foo1() { Base::DoSomething(); }
void Foo2() { Base::DoInternal(); std::cout &

當然,實際寫代碼時,代碼復用一般使用組合 (compose)。但有時繼承更合適,我寫代碼中使用它最典型的兩個場景是:(1) 復用的函數在 Base 中可申明為 protected,隱藏可見性;(2) 極度摳內存的地方,能利用 Base 類 layout 對齊空閑出來的尾部位元組。


你這想法還是太保守了,應該直接問

C++ protected繼承和private繼承是不是沒用的廢物??

www.zhihu.com圖標

如果你覺得protected和private繼承沒有意義,只需要public繼承,那麼「派生類向基類轉化」就是普適的,到處都能用,成員函數中當然也能用。

如果你覺得protected和private繼承有意義,是簡化代碼復用的重要手段,那麼為了傳遞參數,成員函數中的「派生類向基類轉化」當然是需要的。

class FooImpl {
protected:
bool equal_to(const FooImpl) const;
};
class Foo : private FooImpl {
public:
bool equal_to(const Foo other) const {
return FooImpl::equal_to(other); // 從 other 到 const FooImpl 需要派生類到基類轉換
}
};


哪本書啊?這語言都不通啊... 你看答案下面有直接寫inheritance的例子的,有寫delegation做代碼復用的例子的,光答案就跑偏不同方向了

「派生類的成員函數能使用派生類到基類的轉換。」

這裡「派生類的成員函數」是主語,「能使用」是動詞,「派生類到基類的轉換」賓語。

什麼叫成員函數能夠使用轉換啊?我的理解就是method一調用,自己類型就轉換成基類了?


沒必要是成員函數,只要知道派生類和基類關係的都可以轉化


基類顯然不是為了多態性,它提供預設做法。

比如基類的構造函數,如果派生類不去調用,難道要派生類負責基類成員的初始化?

你想想是不是這個道理!


在派生類中,基類與派生類自動滿足父子關係,一般使用場景無須進行如此轉換。參見《C++程序設計精要教程》,在三種情況下會滿足父子關係,這些情況均無須轉換。據知,目前包括外國及國內教材,幾乎沒有討論這個問題的。只有一種情況是必要轉換的,目的是強制編譯器調用基類的函數(否則可能調用派生類的同名函數),參見《C++程序設計精要教程》雙棧模擬實現隊列的operator=重載例子;不過也可以用另一種方法實現,避免派生類對象向基類轉換,因為operator=的顯式參數表的父類引用,可以直接引用滿足父子關係的派生類對象,只要想辦法調用基類的operator=函數即可。


對於繼承非虛基類的里氏轉換屬於窄化,否則是屬於多態


在c中,

char str[20];

void *ptr;

ptr = (void *)str;

傳參ptr

char *parent_str ;

parent_str=(char *)ptr

也就這樣。

c++中好歹有個基類派生類的限定,也就是就是只知道未來傳來的 某個變數 是 某個基類 的派生 。具體是哪個派生類,不知道。

所謂多態。


這樣的特性恰恰是作為介面設計最好的特徵啊。

我為這個問題寫了段代碼,其中Base作為圖形繪製介面提供了坐標和繪製函數

在Base的基礎上可以拓展出圓形繪製、方形繪製、三角形繪製……

作為介面調用者,並不需要具體每一個繪製是怎樣實現的,只要調用Base的繪製函數就好了。

#include &
#include &
using namespace std;

// 基類,對外提供了繪製介面draw
class Base
{
public :
Base(){}
virtual void draw() = 0;
protected:
uint32_t x;
uint32_t y;
};

class Rectangle : public Base
{
public:
Rectangle(){}
// 實現自身的繪製
void draw(){
cout & drawVector;
// 派生類轉換成基類,存放到基類的容器里
drawVector.emplace_back(new Rectangle);
drawVector.emplace_back(new Circle);
// 通過基類調用統一介面
for(auto base: drawVector){
base-&>draw();
}
return 0;
}


推薦閱讀:
相关文章