为什么需要(为了使其编译)中间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::Clonen";
return new Base(*this);
}
};
struct Derived : public Base {
virtual Derived *Clone() const override {
std::cout << "Derived::Clonen";
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::Clonen";
return std::shared_ptr< Base >(new Base(*this));
}
};
struct Derived : public Base {
virtual std::shared_ptr< Derived > Clone() const override {
std::cout << "Derived::Clonen";
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::Clonen";
return CloneImplementation();
}
private:
virtual std::shared_ptr< Base > CloneImplementation() const {
std::cout << "Base::CloneImplementationn";
return std::shared_ptr< Base >(new Base(*this));
}
};
struct Derived : public Base {
std::shared_ptr< Derived > Clone() const {
std::cout << "Derived::Clonen";
return std::static_pointer_cast< Derived >(CloneImplementation());
}
private:
virtual std::shared_ptr< Base > CloneImplementation() const override {
std::cout << "Derived::CloneImplementationn";
return std::shared_ptr< Derived >(new Derived(*this));
}
};
int main() {
Base *b = new Derived;
b->Clone();
}
C++中的一般规则是重写函数必须与它覆盖的函数具有相同的签名。唯一的区别是指针和引用上允许协方差:如果继承的函数返回A*
或A&
,则覆盖器可以分别返回B*
或B&
,只要A
是B
的基类。此规则允许第1节工作。
另一方面,std::shared_ptr<Derived>
和std::shared_ptr<Base>
是两种完全不同的类型,它们之间没有继承关系。因此,无法从覆盖程序返回一个而不是另一个。第 2节在概念上与尝试用std::string f() override
覆盖virtual int f()
相同。
这就是为什么需要一些额外的机制来使智能指针协同行为的原因。您作为第3节展示的就是这样一种可能的机制。这是最通用的一种,但在某些情况下,也存在替代方案。例如:
struct Base {
std::shared_ptr< Base > Clone() const {
std::cout << "Base::Clonen";
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::Clonen";
return std::shared_ptr< Derived >(CloneImplementation());
}
private:
virtual Derived* CloneImplementation() const override {
std::cout << "Derived::CloneImplementationn";
return new Derived(*this);
}
};