C 抽象基類函式如何按值返回子類?

時間 2021-05-11 20:37:26

1樓:Lee Revere

CRTP 可以

template

T>class

Iterator

;class

Derived

;template

<>class

Iterator

>};class

Derived

:public

Iterator

>{};begin() and end()

template

>class

Base

;class

Derived

;template

>class

Iter

;// 對於每乙個子類都定義乙個基類。

template

<>class

Base

>;Iter

>end()

};class

Derived

:public

Base

>;

2樓:

無解。這麼寫會有問題。

Iter* it = rand() ? new MyIter() : new YourIter();

auto ret = it->operator++(114514); // what type of ret???

這不是抽象類不能做返回型別的問題,只要是虛函式,返回型別必須是一樣的(協變的)。只有宣告成 Iter* operator++(int) ,然後子類 MyIter* operator++(int) 才能解決型別衝突問題,這樣 it->operator++(1926817) 就算呼叫子類的 operator++ ,返回型別也一定是父類的 Iter* 。

如果返回型別不能協變的話,這就是無解的。

有人提到 CRTP ,確實可以解決型別問題,但是沒什麼用。如果抽象類是模板的話,難道你的介面要設計成這樣麼:

template

void f(Iter* it);

那我還不如用 concept :

template

void f(T* it);算了。

3樓:傳統的幻想書屋

你的子類的Iter跟父類的Iter沒有半毛錢關係,返回值都不一樣了,你這裡的Iterator更像是乙個要求可迭代的介面約束。不需要動態繫結的話,其實不需要繼承基類。你只需要乙個約束就可以了,可以使用concept,沒有concept支援的話,使用現有的type traits工具也能做,不過比較難看。

貼乙個用Concept實現的簡易demo。

#include

#include

#include

#include

template

T>concept

Range

=requires(T

t)->std::

same_as

.end

())>

;//兩個函式返回值型別要一樣

};//實際上還要約束返回值是一種迭代器,這裡省略了

//定義三個類,實現情況如下

struct

Container1

intend

()};

struct

Container2

};struct

Container3

intend

()const

};//要求乙個滿足Range要求的型別Iter

template

Iter

>void

func

(const

Iter&c

)int

main

(int

argc

,char

const

*argv

)/Users/li/CLionProjects/test/main.cpp: In function 'int main(int, const char**)':

/Users/li/CLionProjects/test/main.cpp:86:

12: error: use of function 'void func(const Iter&) [with Iter = Container1]' with unsatisfied constraints

86 | func(c1Users/li/CLionProjects/test/main.cpp:28:6: note: declared here

28 | void func(const Iter& cUsers/li/CLionProjects/test/main.cpp:28:

6: note: constraints not satisfied

/Users/li/CLionProjects/test/main.cpp: In instantiation of 'void func(const Iter&) [with Iter = Container1]':

/Users/li/CLionProjects/test/main.cpp:86:12: required from here

/Users/li/CLionProjects/test/main.cpp:6:

9: required for the satisfaction of 'Range' [with Iter = Container1]

/Users/li/CLionProjects/test/main.cpp:6:

17: in requirements with 'T t' [with T = Container1]

/Users/li/CLionProjects/test/main.cpp:10:

13: note: 't.

begin()' does not satisfy return-type-requirement

10 | ->std::same_as; //對於Container1型別,這裡不滿足begin和end返回值相同的要求,報錯cc1plus: note:

set '-fconcepts-diagnostics-depth=' to at least 2 for more detail

/Users/li/CLionProjects/test/main.cpp:87:

12: error: use of function 'void func(const Iter&) [with Iter = Container2]' with unsatisfied constraints

87 | func(c2Users/li/CLionProjects/test/main.cpp:28:6: note: declared here

28 | void func(const Iter& cUsers/li/CLionProjects/test/main.cpp:28:

6: note: constraints not satisfied

/Users/li/CLionProjects/test/main.cpp: In instantiation of 'void func(const Iter&) [with Iter = Container2]':

/Users/li/CLionProjects/test/main.cpp:87:12: required from here

/Users/li/CLionProjects/test/main.cpp:6:

9: required for the satisfaction of 'Range' [with Iter = Container2]

/Users/li/CLionProjects/test/main.cpp:6:

17: in requirements with 'T t' [with T = Container2]

/Users/li/CLionProjects/test/main.cpp:9:

10: note: the required expression 't.

end()' is invalid

9 | t.end();//對於Container2型別,這裡不滿足擁有乙個叫end的成員函式,也報錯Users/li/CLionProjects/test/main.cpp:

10:13: note:

't.begin()' does not satisfy return-type-requirement

10 | ->std::same_asfunc(c3)呼叫沒有報錯,因為其完全符合Range的概念要求

如果你要求乙個可迭代的物件,那麼也可以實現

template

concept ForwardIterator=requires(T i,T jvoid)iii!=ji要求過載了前後置自增,比較,解引用運算子

template

concept BackwardIterator=requires(T i,T j)

; //同上

//標準庫里有類似的Concept,不過比這個約束要更全面一些,比如約束*運算子必須返回引用之類的。

template

requires requires(Iter it) //要求滿足ForwardIterator 並且其解引用的結果可以使用cout列印

void Test(Iter first,Iter last)

template

requires requires(Iter it) //要求滿足BackwardIterator 並且其解引用的結果可以使用cout列印

void Test(Iter first,Iter last)

int main(int argc, char const *argvstd::forward_list intList;

std::forward_list containerList,,,,};//這是Container1是第乙個測試裡那個型別

Test(intList.begin(),intList.end());//編譯通過

Test(containerList.begin(),containerList.end());//編譯報錯

return 0;

} 執行上面的測試,第二個Test函式沒注釋掉,編譯器報錯

/Users/li/CLionProjects/test/main.cpp:53:

38: note: the required expression '(std::

cout << (* it))' is invalid

53 | requires requires(Iter it)

Container1沒過載<<,無法通過cout列印編譯不通過。注釋掉第二個Test函式,編譯通過。

執行程式,列印結果,可以看到呼叫的正是第乙個要求ForwardIterator的函式,因為std::forward_list是單鏈表,其迭代器只能自增,不能自減,只能匹配第乙個Test函式。

ForwardIterator

1 2 3 4 5

Process finished with exit code 0

然後就是你的需求了。你想要乙個約束,要求滿足約束的類必須有乙個begin函式,返回其自己的迭代器型別物件,然後這個迭代器型別又必須滿足能夠自增的約束。

#include

#include

#include

template

concept Iterator=requires (T tt;

};//Iterator約束要求實現operator++(int)

template

concept Base = requires(std::add_const_t t)//要求begin必須是const成員函式

->Iterator;

};//要求Base約束的型別,有個begin函式,且返回值滿足Iterator約束

struct ImplClass1;}

};//可以選擇返回任意型別,只要滿足Iterator約束,這裡int是滿足的,但是std::vector不滿足,所以後面編譯報錯

struct ImplClass3;

template

void test(const T& t)

int main(int argc, char const *argvImplClass1 i1;

ImplClass2 i2;

ImplClass3 i3;

test(i1);

test(i2);

test(i3);

return 0;

}後兩個test報錯

/Users/li/CLionProjects/test/main.cpp: In function 'int main(int, const char**)':

/Users/li/CLionProjects/test/main.cpp:44:

12: error: use of function 'void test(const T&) [with T = ImplClass2]' with unsatisfied constraints

44 | test(i2Users/li/CLionProjects/test/main.cpp:32:6: note: declared here

32 | void test(const T& tUsers/li/CLionProjects/test/main.cpp:32:

6: note: constraints not satisfied

/Users/li/CLionProjects/test/main.cpp: In instantiation of 'void test(const T&) [with T = ImplClass2]':

/Users/li/CLionProjects/test/main.cpp:44:12: required from here

/Users/li/CLionProjects/test/main.cpp:14:

9: required for the satisfaction of 'Base' [with T = ImplClass2]

/Users/li/CLionProjects/test/main.cpp:14:

16: in requirements with 'std::add_const_t t' [with _Tp = ImplClass2; T = ImplClass2]

/Users/li/CLionProjects/test/main.cpp:16:

13: note: 't.

begin()' does not satisfy return-type-requirement

16 | ->Iterator; //返回值std::vector沒有++過載運算子,不滿足Iterator約束,報錯cc1plus: note:

set '-fconcepts-diagnostics-depth=' to at least 2 for more detail

/Users/li/CLionProjects/test/main.cpp:45:

12: error: use of function 'void test(const T&) [with T = ImplClass3]' with unsatisfied constraints

45 | test(i3Users/li/CLionProjects/test/main.cpp:32:6: note: declared here

32 | void test(const T& tUsers/li/CLionProjects/test/main.cpp:32:

6: note: constraints not satisfied

/Users/li/CLionProjects/test/main.cpp: In instantiation of 'void test(const T&) [with T = ImplClass3]':

/Users/li/CLionProjects/test/main.cpp:45:12: required from here

/Users/li/CLionProjects/test/main.cpp:14:

9: required for the satisfaction of 'Base' [with T = ImplClass3]

/Users/li/CLionProjects/test/main.cpp:14:

16: in requirements with 'std::add_const_t t' [with _Tp = ImplClass3; T = ImplClass3]

/Users/li/CLionProjects/test/main.cpp:16:

13: note: the required expression 't.

begin()' is invalid

16 | ->Iterator; //沒有begin函式,報錯

c++20之前沒有概念,寫這個東西非常麻煩,報錯不是人看的,有了概念就能很方便的進行泛型約束了,用於編譯期多型,要執行期多型還是要虛函式。可以兩者根據需求結合使用,非常強大。

C 如何在類中定義乙個 C 函式(不用傳遞 this,非友元,非靜態)?

悽臨雨 無捕獲的lambda,可以轉型為c函式指標。類內巢狀類可以定義靜態函式 不一定合乎要求 但據我所知都只能獲取指標,沒辦法定義c函式 因為c函式應當處在c的命名空間中 陸海綿 使用函式指標成員指向乙個類外定義的C函式。extern c class Avoid p int 實在想不到哪種應用場景...

c語言如何定義沒有返回值的main函式

張浩 永遠都應該寫成int main void 或者int main int argc,char argv void main?不知道從哪傳出來的寫法 穀雨同學 無論如何,使用void作為返回值型別的main函式都是不符合標準的。請在任何情況下都避免這樣寫。但是main函式可以不寫return語句,...

C 抽象類作為模板引數,當其為指標時,如何析構?

小明 別總想著只要是物件就要new,多用RAII解決資源問題。首先你的linklist初始化就不要new.你要做的是過載 operator 接著linklist繼承的是linerlist是如何實現,為啥抽象基類要具體化,你只是使用他的指標。多用智慧型指標,如果嫌棄智慧型指標,就學一下智慧型指標的思路...