[英]Polymorphic unique_ptr class member
我想有一個指向基類的unique_ptr類成員,但稍后在構造函數中通過多態可以更改為指向同樣基類的姐妹類。
雖然我沒有在構造函數中設置此多態性時出現任何錯誤,但它似乎無法正常工作,因為我收到錯誤消息,我的多態指針無法找到我認為指針現在的姐妹類的成員指點。
我如何在這里正確實現多態?
class A {
int bar;
};
class B : public A {
int foo;
};
class C: public A {
C();
std::unique_ptr<A> _ptr; // changing to std::unique_ptr<B> _ptr removes the "class A has no member 'foo'" error
};
C::C() : A()
{
_ptr = std::make_unique<B>(); // no errors here
int w = _ptr->foo; // class A has no member 'foo'
}
當你分配
_ptr = std::make_unique<B>();
這是有效的,因為B
是A
的派生類,但是_ptr
仍然是基類的unique_ptr
。 聲明后,您無法更改變量的類型。
那么你有什么選擇呢?
因為您知道_ptr
存儲指向派生類B
的指針,所以您可以在解除引用后執行轉換:
_ptr = std::make_unique<B>();
// derefence the pointer, and cast the reference to `B&`.
B& reference_to_sister = (B&)(*_ptr);
int w = reference_to_sister.foo;
如果你采用這種方法,你將不得不以某種方式跟蹤_ptr
的哪個派生類,否則你將面臨運行bug的風險。
或者,如果您使用的是C ++ 17,則可以使用std::variant
:
class C : public A {
void initialize(A& a) {
// Do stuff if it's the base class
}
void initialize(B& b) {
// Do different stuff if it's derived
int w = b.foo;
}
C() {
_ptr = std::make_unique<B>(); // This works
// This takes the pointer, and calls 'initialize'
auto initialize_func = [&](auto& ptr) { initialize(*ptr); };
// This will call 'initialize(A&)' if it contains A,
// and it'll call 'initialize(B&)' if it contains B
std::visit(initialize_func, _ptr);
}
std::variant<std::unique_ptr<A>, std::unique_ptr<B>> _ptr;
};
實際上,如果使用std::variant
即使A
和B
是完全不相關的類,這也會起作用。
這是另一個簡短的variant
示例
#include <variant>
#include <string>
#include <iostream>
void print(std::string& s) {
std::cout << "String: " << s << '\n';
}
void print(int i) {
std::cout << "Int: " << i << '\n';
}
void print_either(std::variant<std::string, int>& v) {
// This calls `print(std::string&) if v contained a string
// And it calls `print(int)` if v contained an int
std::visit([](auto& val) { print(val); }, v);
}
int main() {
// v is empty right now
std::variant<std::string, int> v;
// Put a string in v:
v = std::string("Hello, world");
print_either(v); //Prints "String: Hello, world"
// Put an int in v:
v = 13;
print_either(v); //Prints "Int: 13"
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.