在 C++ 中我们可以这样做:
struct Base
{
virtual Base* Clone() const { ... }
virtual ~Base(){}
};
struct Derived : Base
{
virtual Derived* Clone() const {...} //overrides Base::Clone
};
但是,以下内容不会起到同样的作用:
struct Base
{
virtual shared_ptr<Base> Clone() const { ... }
virtual ~Base(){}
};
struct Derived : Base
{
virtual shared_ptr<Derived> Clone() const {...} //hides Base::Clone
};
在此示例中,
Derived::Clone
隐藏Base::Clone
而不是覆盖它,因为标准规定覆盖成员的返回类型只能从引用(或指针)更改为基类到引用(或指针) ) 来导出。有什么聪明的解决方法吗?当然,有人可能会争辩说 Clone
函数无论如何都应该返回一个普通的指针,但让我们暂时忘记它 - 这只是一个说明性示例。我正在寻找一种方法来将虚拟函数的返回类型从智能指针更改为 Base
到智能指针Derived
。
提前致谢!
更新:我的第二个例子确实无法编译,感谢Iammilind
您无法直接执行此操作,但有几种方法可以在非虚拟接口习惯用法的帮助下进行模拟。
struct Base
{
private:
virtual Base* doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }
virtual ~Base(){}
};
struct Derived : Base
{
private:
virtual Derived* doClone() const { ... }
public:
shared_ptr<Derived> Clone() const { return shared_ptr<Derived>(doClone()); }
};
这仅在您实际上有一个原始指针开始时才有效。
struct Base
{
private:
virtual shared_ptr<Base> doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return doClone(); }
virtual ~Base(){}
};
struct Derived : Base
{
private:
virtual shared_ptr<Base> doClone() const { ... }
public:
shared_ptr<Derived> Clone() const
{ return static_pointer_cast<Derived>(doClone()); }
};
在这里,您必须确保
Derived::doClone
的所有重写实际上返回指向 Derived
或从它派生的类的指针。
@ymett 使用 CRTP 技术对出色的 answer 进行了改进。这样您就不必担心忘记在 Derived 中添加非虚函数。
struct Base
{
private:
virtual Base* doClone() const { ... }
public:
shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }
virtual ~Base(){}
};
template<class T>
struct CRTP_Base : Base
{
public:
shared_ptr<T> Clone() const { return shared_ptr<T>(doClone()); }
};
struct Derived : public CRTP_Base<Derived>
{
private:
virtual Derived* doClone() const { ... }
};
我的脑海中浮现出一些想法。首先,如果您可以执行第一个版本,只需将
Clone
隐藏起来,and 编写另一个受保护的 _clone
实际上返回派生指针。 Clone
都可以使用它。
这就引出了一个问题:你为什么要这样做。另一种方法可能是强制(外部)函数,在该函数中,您收到一个
shared_ptr<Base>
并可以将其强制为 shared_ptr<Derived>
(如果可能)。也许是这样的:
template <typename B, typename D>
shared_ptr<D> coerce(shared_ptr<B>& sb) throw (cannot_coerce)
{
// ...
}
通过创建自动重新路由指针的自动化实现类,您可以更接近真正的协变智能指针返回类型。这种方式也适用于自定义删除器,并且当派生类不具有它们返回的指针的唯一共享所有权时,这也适用。代码如下所示:
class Base{
virtual void print_impl(std::shared_ptr<Base>& base_ptr) = 0;
public:
std::shared_ptr<Base> print() {
std::shared_ptr<Base> base;
print_impl(base);
return base;
}
};
template <typename TBase>
class BaseImpl : public Base{
void print_impl(std::shared_ptr<Base>& base_ptr) override {
auto tbase = create();
base_ptr = tbase;
}
public:
virtual std::shared_ptr<TBase> print() = 0;
};
class Derived : public BaseImpl<Derived> {
public:
std::shared_ptr<Derived> print();
};
在上面的例子中,所有派生类只需实现 std::shared_ptr print();并继承自BaseImpl,其中“Derived”可以是兼容类型。
对于可执行示例:
#include <iostream>
#include <memory>
class Base {
public:
virtual ~Base() {std::cout << "Destroyed\n";}
virtual void print() { std::cout << "Base\n"; }
};
class Derived : public Base {
public:
void print() override { std::cout << "Derived\n"; }
};
class IFactory{
public:
std::shared_ptr<Base> create() {
std::shared_ptr<Base> base;
create_impl(base);
return base;
}
private:
virtual void create_impl(std::shared_ptr<Base>& base_ptr) = 0;
};
template<typename TBase>
class UFactory : public IFactory{
public:
virtual std::shared_ptr<TBase> create() = 0;
private:
virtual void create_impl(std::shared_ptr<Base>& base_ptr) {
auto tbase = create();
shared_ptr = tbase;
}
};
class Factory : public UFactory<Base>{
public:
std::shared_ptr<Base> create() override {
return std::make_shared<Base>();
}
};
class DerivedFactory : public UFactory<Derived> {
public:
std::shared_ptr<Derived> create() override {
return std::make_shared<Derived>();
}
};
int main() {
{
std::shared_ptr<IFactory> factory = std::make_shared<DerivedFactory>();
std::shared_ptr<Base> base = factory->create();
std::cout << typeid(factory->create().get()).name() << std::endl; // Output: Base
base->print(); // Output: Derived
}
std::cout << "-----------" << std::endl;
{
std::shared_ptr<DerivedFactory> factory = std::make_shared<DerivedFactory>();
std::shared_ptr<Base> base = factory->create();
std::cout << typeid(factory->create().get()).name() << std::endl; // Output: Derived
base->print(); // Output: Derived
}
return 0;
}