我非常需要访问特定于派生类的功能,在构造包含类时,我在unique_ptr
中获得了一个实例。然后,此包含类必须将unique_ptr
转换到其基类,再移到包含类的基类构造函数中,并在其中最终move
拥有该基类的所有权。一些代码应该会有所帮助:
class MemberBase {};
class MemberDerived : public MemberBase { /*some public stuff not in MemberBase*/ };
class MainBase {
std::unique_ptr<MemberBase> member_;
public:
MainBase(std::unique_ptr<MemberBase> member) : member_(std::move(member)) {}
};
class MainDerived : public MainBase {
MemberDerived* member_derived_;
// This class proceeds to use MemberDerived-only functions
public:
// How to write the initialization list below?
MainDerived(std::unique_ptr<MemberDerived> member)
: MainBase(std::move(member)),member_derived_(member.get() /*nullptr!!*/) {}
};
忽略整体类设计的问题(我知道耦合到MemberDerived
中特定于MainDerived
的特定函数并不理想;这是继承的代码,如果不进行重大重构就无法更改),在转发unique_ptr
到MainBase
之前,我如何获取原始指针?
在下面找到我已经想到的一些想法,以及为什么我认为这些想法不好。
- 受保护的访问者下传:
// Add this method to the protected section of MainBase:
MemberBase* MainBase::get_member() { return member_.get(); }
// Then downcast in MainDerived's c'tor
MainDerived::MainDerived(std::unique_ptr<MemberDerived> member)
: MainBase(std::move(member)),member_derived_(dynamic_cast<MemberDerived*>(get_member())) {}
这应该可以,但是使用dynamic_cast
(本身的主要缺点),当然,如果有人将传递给c'tor的类型更改为不是从MemberDerived
派生的类型,它将不会中断编译器的帮助。
- 两次传入指针:
// member and member_derived must point to the same object!
MainDerived::MainDerived(std::unique_ptr<MemberDerived> member,MemberDerived* member_derived)
: MainBase(std::move(member)),member_derived_(member_derived) {}
除了创建一个非常丑陋的c'tor签名外,用户在调用move
之前为两个参数传递不同的指针或执行get
也非常容易。此外,现在用户被迫创建一个局部变量以将其传递到两个地方。我说过丑吗?
- 使用辅助功能欺骗性翻转初始化顺序:
template <typename T>
std::unique_ptr<T> ExtractPointer(std::unique_ptr<T> p,T** target) {
*target = p.get();
return std::move(p);
}
MainDerived::MainDerived(std::unique_ptr<MemberDerived> member)
: MainBase(ExtractPointer(std::move(member),&member_derived_)) {}
现在,我实际上感到有些惊讶,因为它没有产生任何警告/错误(带有-Wall
的gcc 5.4.0)。我的部分人喜欢这样做,因为它很难破解,但是member_derived_
的circuit回初始化给我带来了些许寒意。