C++ 中 std::shared_ptr 的克隆模式
Clone pattern for std::shared_ptr in C++
为什么需要(为了使其编译)中间 CloneImplementation
和 std::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();
}
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();
}
输出:
error: invalid covariant return type for 'virtual std::shared_ptr<Derived> Derived::Clone() const'
error: overriding 'virtual std::shared_ptr<Base> Base::Clone() const'
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();
}
C++ 中的一般规则是覆盖函数必须与其覆盖的函数具有相同的签名。唯一的区别是指针和引用允许协变:如果继承函数 returns A*
或 A&
,覆盖程序可以 return B*
或 B&
,只要 A
是 B
的基础 class。此规则允许 1 部分起作用。
另一方面,std::shared_ptr<Derived>
和std::shared_ptr<Base>
是两个完全不同的类型,它们之间没有继承关系。因此,不可能 return 一个而不是另一个覆盖程序。 2 部分在概念上与尝试用 std::string f() override
.
覆盖 virtual int f()
相同
这就是为什么需要 一些 额外的机制来使智能指针行为协变。您在第 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);
}
};
为什么需要(为了使其编译)中间 CloneImplementation
和 std::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();
}
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();
}
输出:
error: invalid covariant return type for 'virtual std::shared_ptr<Derived> Derived::Clone() const'
error: overriding 'virtual std::shared_ptr<Base> Base::Clone() const'
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();
}
C++ 中的一般规则是覆盖函数必须与其覆盖的函数具有相同的签名。唯一的区别是指针和引用允许协变:如果继承函数 returns A*
或 A&
,覆盖程序可以 return B*
或 B&
,只要 A
是 B
的基础 class。此规则允许 1 部分起作用。
另一方面,std::shared_ptr<Derived>
和std::shared_ptr<Base>
是两个完全不同的类型,它们之间没有继承关系。因此,不可能 return 一个而不是另一个覆盖程序。 2 部分在概念上与尝试用 std::string f() override
.
virtual int f()
相同
这就是为什么需要 一些 额外的机制来使智能指针行为协变。您在第 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);
}
};