第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

多態(tài)性的 C++ 模板?“使用類模板需要模板參數(shù)”

多態(tài)性的 C++ 模板?“使用類模板需要模板參數(shù)”

侃侃無極 2023-05-10 13:32:48
我是 C++ 的新手,正在嘗試弄清楚如何使用模板來構(gòu)建特定類型的類的層次結(jié)構(gòu)以實現(xiàn)多態(tài)性。我知道如何使用泛型在 Java 中很容易地做到這一點。我確定之前有人問過這個問題,但我只是不知道在 C++ 中使用什么術(shù)語來搜索我想要的內(nèi)容。我希望能夠使用我創(chuàng)建的基類,該基類使用由下面定義的非常指定的類Derived_1和組成的對象組合創(chuàng)建Derived_2,每個類都從名為 的類擴(kuò)展Base。但是,我收到一個編譯器錯誤提示我需要聲明類型?我使用什么語法來指示z在實現(xiàn)中使用的這個向量可以由從 擴(kuò)展的類的任意組合組成Base?到目前為止,這是我所擁有的,我認(rèn)為在聲明基類和擴(kuò)展該基類的類時大部分是正確的:base_types.htemplate <typename T>class Base {public:    Base<T>(size_t a, T b) :            m_a(a),            m_b(b) {    }    T getB() const;    size_t m_a;    T m_b;};// specific kind of Base that uses boolclass Derived_1 : public Base<bool> {    Derived_1(uint32_t a);     // second parameter is unused, is assumed to be "true"    bool getB();};// specific kind of Base that uses size_tclass Derived_2 : public Base<size_t> {    Derived_2(uint32_t a, size_t b);    size_t getB();};基礎(chǔ)類型.cppDerived_1::Derived_1(uint32_t a) : Base(a, true) { }      // second parameter is unused, is assumed to be "true"bool Derived_1::getB() { return m_b; }Derived_2::Derived_2(uint32_t a, size_t b) : Base(a, b) { }bool Derived_2::getB() { return m_b; }impl_types.h#include "base_types.h"#include <vector>class Foo {public:    Foo(        size_t y,        const std::vector<Base>& z);      // Error: Use of class template 'Base' requires template arguments};impl_types.cppclass Foo {public:    Foo(        size_t y,        const std::vector<Base>& z) :      // Error: Use of class template 'Base' requires template arguments            m_y{y},            m_z{z};};作為參考,這是我想做的事情的 Java 實現(xiàn):// Base.javaclass Base<T> {    int m_a;    T m_b;    Base(int a, T b) {        m_a = a;        m_b = b;    }    T getB() {        return m_b;    }}// Derived_1.javaclass Derived_1 extends Base<Boolean> {    Derived_1(int a, Boolean a) {        super(a, b);    }    Boolean getB() {        return m_b;    }}// Derived_2.javaclass Derived_2 extends Base<String> {    Derived_2(int a, String b) {        super(a, b);    }    String getB() {        return m_b;    }}
查看完整描述

4 回答

?
月關(guān)寶盒

TA貢獻(xiàn)1772條經(jīng)驗 獲得超5個贊

在 Java 中,這是可行的,因為 aArrayList<Widget>基本上是ArrayList<Object>. 這有一些優(yōu)點,但也有缺點。


在 C++ 中,有模板而不是泛型。出于相似的目標(biāo),它們在實現(xiàn)和含義方面有很大不同。


正如他們的名字所說:他們是模板。類模板不是類。它是某種只存在于編譯時的實體。只有當(dāng)模板被實例化時,它才會變得具體。


ELI5關(guān)于實例化一個模板的過程:std::vector就是模板。std::vector<int>是模板的實例化。模板通過填充代碼的漏洞來實例化,由模板參數(shù)表示:


template<typename T>

auto value() -> T { return T{}; }


int main() {

? ? return value<int>() + value<short>();

}

實例化了兩個函數(shù),看起來像這樣:


template<> //? ?v---- T has been replaced!

auto value() -> int { return int{}; }


template<> // Another instantiation

auto value() -> short { return short{}; }

當(dāng)然,編譯器不會以文本方式替換它,而是使用 AST 來解析實際類型。


這是為了向您展示模板在該過程之后并不真正存在。只有實例化是具體的。并且有多個實例化。


就像上面的函數(shù)模板一樣,當(dāng)一個模板類被實例化時,一個全新的類型就被創(chuàng)建了。實例化創(chuàng)建的類型完全不相關(guān)。它們只是不同的類型,就像模板函數(shù)產(chǎn)生不同的實例一樣。


那么...如果您有許多不同的、不相關(guān)的類,您如何實現(xiàn)多態(tài)性呢?


你加個接口!


struct Interface {

? ? // TODO: put useful function there

};


template<typename T>

struct Base : Interface {

? ? virtual auto getB() const -> T;

};


struct Impl1 : Base<bool> {

? ? auto getB() const -> T override;

};

如果相反,你的意圖是做這樣的事情:


Base b = ...;


// pseudocode

if (typeid(b->getB()) == bool)

{

? ? bool b = dynamic_cast<bool>(b->getB());

}

else if (typeid(b->getB()) == std::size_t)

{

? ? std::size_t b = dynamic_cast<std::size_t>(b->getB());

}

然后,像其他答案一樣,一個變體就是解決方案。Base如果你像這樣列出可能的類型,那么你就提前知道了可能類型的列表。所以 astd::variant就是你想要的。


為了使變體更易于使用,您始終可以為類型添加別名:


using VBase = std::variant<Base<bool>, Base<std::size_t>, ...>

查看完整回答
反對 回復(fù) 2023-05-10
?
天涯盡頭無女友

TA貢獻(xiàn)1831條經(jīng)驗 獲得超9個贊

你不能std::vector<Base>因為Base是模板。你應(yīng)該有std::vector<Base<bool>>,std::vector<Base<size_t>> 或者類似的。Base<bool>并且Base<size_t>是不同的類型,除了使用相同的模板制作之外沒有其他共同之處Base。

可能是您想要的,std::vector<std::variant<Base<bool>,Base<size_t>>>但很難從您的代碼中分辨出來。用于std::variant具有可以具有不同類型值的變量(可能沒有共同點)。

您不能將派生類的對象放入基類的向量中,因此std::vector<std::variant<Derived1,Derived2>>當(dāng)您希望它們按值在同一向量中時應(yīng)該使用。動態(tài)多態(tài)對象必須具有完全相同的基類,即使這樣您也需要通過引用而不是值將它們放入容器中。


查看完整回答
反對 回復(fù) 2023-05-10
?
回首憶惘然

TA貢獻(xiàn)1847條經(jīng)驗 獲得超11個贊

如果你創(chuàng)建一個非模板化的空基類,一個從它繼承的模板,然后是特化,你可以將基指針存儲在一個向量或任何其他結(jié)構(gòu)中。如果你想使用存儲的對象,你必須明確地將它們轉(zhuǎn)換回實際類型(如果我是正確的話,這也必須在 Java 中完成)。



查看完整回答
反對 回復(fù) 2023-05-10
?
慕蓋茨4494581

TA貢獻(xiàn)1850條經(jīng)驗 獲得超11個贊

錯誤:使用類模板Base需要模板參數(shù)

你得到錯誤是因為它Base不是一個類型,而只是一個模板。不要將 C++ 模板與 Java 泛型混淆,它們實際上是非常不同的概念。您不能擁有模板向量,因為模板只是模板。您需要實例化它們以獲得類型。例如,您可以有一個std::vector<Base<bool>>.

您的代碼中的另一個問題是Base應(yīng)該有一個虛擬析構(gòu)函數(shù)。否則你有內(nèi)存泄漏的危險。必須聲明方法以virtual啟用動態(tài)分派。

話雖如此...

你真正想做什么:

我只是想持有一個從公共基類繼承的不同類對象的向量,[...]

你不需要模板。這很簡單:

#include <iostream>

#include <vector>

#include <memory>

#include <utility>

struct base {?

? ? virtual void some_method(){ std::cout << "base\n";}

? ? virtual ~base(){}

};

struct foo : base {

? ? virtual void some_method() override { std::cout << "foo\n";}

};

struct bar : base {

? ? virtual void some_method() override { std::cout << "bar\n";}

};



int main() {

? ? std::vector<std::shared_ptr<base>> v;

? ? v.emplace_back(new foo());

? ? v.emplace_back(new bar());


? ? for (auto& e : v) e->some_method();

? ? return 0;

}

多態(tài)性適用于指針或引用。由于在容器中存儲引用并不是那么簡單,所以我使用了指針。我使用智能指針,因為我不想在手動內(nèi)存管理上亂來。


到目前為止,一切都很好...


[...] 但是使用在那些返回不同類型的類之間共享的方法,具體取決于該特定類


然而,這并不容易。首先,注意同一個方法不能有不同的返回類型。舉個例子,如果你有


struct example_base {?

? ? virtual int foo() { return 1;}?

};

struct example_derived {

? ? virtual double foo() override { return 1.4; }

};

然后example_derived::foo不覆蓋!_ example_base::foo感謝override編譯器會通過一條錯誤消息告訴你


prog.cc:20:24: error: 'foo' marked 'override' but does not override any member functions

? ? ? ? virtual double foo() override { return 1.4; }

? ? ? ? ? ? ? ? ? ? ? ?^

根據(jù)您實際想要實現(xiàn)的目標(biāo)(為什么您需要派生以不同的返回類型“共享一個通用方法”?),有不同的方法可以解決這個問題。我會告訴你一種方法。


#include <iostream>

#include <vector>

#include <memory>

#include <utility>


struct return_type_base {?

? ? virtual void print() {}

? ? virtual ~return_type_base() {}

};


struct bool_return_type : return_type_base {

? ? bool value = true;

? ? virtual void print() { std::cout << value << "\n"; }

};

struct int_return_type : return_type_base {

? ? int value = 3;

? ? virtual void print() { std::cout << value << "\n"; }

};


using return_type_ptr = std::shared_ptr<return_type_base>;


struct base {?

? ? virtual return_type_ptr some_method() = 0;

? ? virtual ~base(){}

};

struct foo : base {

? ? virtual return_type_ptr some_method() override {?

? ? ? ? return return_type_ptr(new bool_return_type());

? ? }

};

struct bar : base {

? ? virtual std::shared_ptr<return_type_base> some_method() override {?

? ? ? ? return return_type_ptr(new int_return_type());

? ? }

};



int main() {

? ? std::vector<std::shared_ptr<base>> v;

? ? v.emplace_back(new foo());

? ? v.emplace_back(new bar());


? ? for (auto& e : v) e->some_method()->print();

? ? return 0;

}

它基本上與上面的方法完全相同。為了以多態(tài)方式處理不同的類型,我們聲明了一個公共基類并處理該基類的共享指針。如前所述,這只是一種可能的方法。請對它持保留態(tài)度,它只是為了給你一個起點。主要缺點是:它是侵入性的(您必須為每個要返回的類型編寫一個類)并且它使用虛函數(shù)(即運(yùn)行時開銷)。有更好的方法,但細(xì)節(jié)對您實際想要對這些不同的返回類型做什么很重要。為了進(jìn)一步閱讀,我建議您搜索“type erasure”。


長話短說


模板是一個純粹的編譯時概念。如果你想在運(yùn)行時平等對待不同的類型,你需要某種形式的運(yùn)行時類型擦除。可用于此的技術(shù)在 Java 和 C++ 中有很大不同。通過虛函數(shù)實現(xiàn)的運(yùn)行時多態(tài)性適用于兩者,并且可能是最容易理解的一種,尤其是當(dāng)您來自 Java 時。您還應(yīng)該看看標(biāo)準(zhǔn)庫必須提供的內(nèi)容 (?std::any,?std::variant)。



查看完整回答
反對 回復(fù) 2023-05-10
  • 4 回答
  • 0 關(guān)注
  • 218 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號