我有一個純虛擬類,BaseClass沒有資料成員和受保護的建構式。它的存在只是為子類(模板化)提供介面。我想要在基類中實作的所有功能。對這些進行操作的函式通常會回傳BaseClass&,以允許方便地鏈接操作。
一切都很好,直到我嘗試拋出一個實體,通過參考從其中一個函式回傳。簡而言之,我拋出了一個抽象類的參考,但我確信它是一個完整構造的子類實體,所有虛函式都完好無損。這就是BaseClass建構式受到保護的原因。我正在針對 C 14 編譯器進行編譯。它拒絕讓我拋出一個抽象類。
類的一個要點是我可以構造一個子類,立即呼叫它上面的函式添加資訊,然后扔掉,一舉一動:
throw String<72>().addInt(__LINE__).addText("mom says no"); //does not compile
但是addText(),非常合理地回傳BaseClass&,編譯器拒絕。
我如何能?將所有成員函式移到子類中似乎很可恥。我可以通過在拋出前靜態轉換整個運算式來解決它:
throw static_cast<String<72&>( //works, ugly
BaseClassString<72>().addText(where).addText(why).addText(resolution));
甚至創建一個宏來隱藏丑陋的機制并確保一些安全,但我錯過了什么嗎?這似乎是 C 阻止了一種完全可行的技術的情況。
uj5u.com熱心網友回復:
為什么我不能拋出一個抽象類?
由于[except.throw]
/3拋出例外復制初始化([dcl.init], [class.copy.ctor])一個臨時物件,稱為例外物件。
/5當拋出的物件是類物件時,復制初始化選擇的建構式以及考慮拋出的物件作為左值的復制初始化選擇的建構式應是不可洗掉和可訪問的,即使復制/移動操作被省略([class.copy.elision])。
uj5u.com熱心網友回復:
throw您可以通過virtual void Throw() const成員函式擁有派生類本身。這將消除呼叫現場的演員陣容。其原理類似于具有用于多型復制的虛擬克隆功能。
#include <iostream>
#include <sstream>
#include <string>
#include <variant>
#include <vector>
using std::cout;
using std::get;
using std::holds_alternative;
using std::ostream;
using std::ostringstream;
using std::string;
using std::variant;
using std::vector;
class Abc {
using info_t = variant<int, string>;
vector<info_t> v;
virtual auto subtext() const -> string = 0;
public:
virtual ~Abc();
Abc() = default;
Abc(Abc const&) = default;
auto addInt(int) -> Abc&;
auto addText(string) -> Abc&;
virtual void Throw[[noreturn]]() const = 0;
virtual void print(ostream&) const;
};
Abc::~Abc() = default;
auto Abc::addInt(int value) -> Abc& {
v.push_back(value);
return *this;
}
auto Abc::addText(string value) -> Abc& {
v.push_back(value);
return *this;
}
void Abc::print(ostream& out) const {
if (auto st = subtext(); !st.empty())
out << st << "\n";
for (auto&& x : v) {
if (holds_alternative<int>(x)) {
out << get<int>(x) << "\n";
} else if (holds_alternative<string>(x)) {
out << get<string>(x) << "\n";
} else {
out << "(unknown type)\n";
}
}
}
template <typename T>
class Concrete : public Abc {
T data;
auto subtext() const -> string override {
ostringstream ss;
ss << data;
return ss.str();
}
public:
Concrete(T value) : data{value} {}
void Throw[[noreturn]]() const override { throw *this; }
};
struct allow_ctad_t;
Concrete(allow_ctad_t)->Concrete<void>;
int main() {
try {
Concrete(1000).addInt(__LINE__).addText(__FILE__).addText("Just testing!").Throw();
} catch (Abc const& ex) {
ex.print(cout);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/493786.html
