C++ 中 std::shared_ptr 的克隆模式

Mat*_*ias 5 overriding clone virtual-functions smart-pointers c++11

为什么需要(为了使其编译)中间体CloneImplementationstd::static_pointer_cast(参见下面的第3节)使用克隆模式std::shared_ptr而不是更接近(参见下面的第2节)使用原始指针(参见下面的第1节)?因为据我所知,std::shared_ptr有一个广义的复制构造函数和一个广义的赋值运算符?

1. 带有原始指针的克隆模式

#include <iostream>

struct Base {
    virtual Base *Clone() const {
        std::cout << "Base::Clone\n";
        return new Base(*this);
    }
};

struct Derived : public Base {
    virtual Derived *Clone() const override {
        std::cout << "Derived::Clone\n";
        return new Derived(*this);
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}
Run Code Online (Sandbox Code Playgroud)

2. 共享指针的克隆模式(幼稚的尝试)

#include <iostream>
#include <memory>

struct Base {
    virtual std::shared_ptr< Base > Clone() const {
        std::cout << "Base::Clone\n";
        return std::shared_ptr< Base >(new Base(*this));
    }
};
struct Derived : public Base {
    virtual std::shared_ptr< Derived > Clone() const override {
        std::cout << "Derived::Clone\n";
        return std::shared_ptr< Derived >(new Derived(*this));
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}
Run Code Online (Sandbox Code Playgroud)

输出:

error: invalid covariant return type for 'virtual std::shared_ptr<Derived> Derived::Clone() const'
error:   overriding 'virtual std::shared_ptr<Base> Base::Clone() const'
Run Code Online (Sandbox Code Playgroud)

3. 共享指针的克隆模式

#include <iostream>
#include <memory>

struct Base {

    std::shared_ptr< Base > Clone() const {
        std::cout << "Base::Clone\n";
        return CloneImplementation();
    }

private:

    virtual std::shared_ptr< Base > CloneImplementation() const {
        std::cout << "Base::CloneImplementation\n";
        return std::shared_ptr< Base >(new Base(*this));
    }
};
struct Derived : public Base {

    std::shared_ptr< Derived > Clone() const {
        std::cout << "Derived::Clone\n";
        return std::static_pointer_cast< Derived >(CloneImplementation());
    }

private:

    virtual std::shared_ptr< Base > CloneImplementation() const override {
        std::cout << "Derived::CloneImplementation\n";
        return std::shared_ptr< Derived >(new Derived(*this));
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 7

C++ 中的一般规则是覆盖函数必须与它覆盖的函数具有相同的签名。唯一的区别是指针和引用允许协方差:如果继承的函数返回A*or A&,则覆盖程序可以分别返回B*or B&,只要A是 的基类B。这条规则允许第1部分工作。

另一方面,std::shared_ptr<Derived>std::shared_ptr<Base>是两种完全不同的类型,它们之间没有继承关系。因此,不可能从覆盖程序返回一个而不是另一个。第2是概念一样试图覆盖virtual int f()std::string f() override

这就是为什么需要一些额外的机制来使智能指针具有协变行为。您在第3节中展示的就是这样一种可能的机制。这是最通用的一种,但在某些情况下,也存在替代方案。例如这个:

struct Base {
    std::shared_ptr< Base > Clone() const {
        std::cout << "Base::Clone\n";
        return std::shared_ptr< Base >(CloneImplementation());
    }

private:
    virtual Base* CloneImplementation() const {
        return new Base(*this);
    }
};

struct Derived : public Base {
     std::shared_ptr< Derived > Clone() const {
        std::cout << "Derived::Clone\n";
        return std::shared_ptr< Derived >(CloneImplementation());
    }

private:
    virtual Derived* CloneImplementation() const override {
        std::cout << "Derived::CloneImplementation\n";
        return new Derived(*this);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • @Matthias 是的,它纯粹是根据派生类的指针或引用来定义的。 (2认同)