我有一个看起来像的函数:
// this function might modify base_ptr
void SomeFunction(shared_ptr<Base> &base_ptr)
{ if(some_condition) { base_ptr = some_other_ptr; } }
我想用shared_ptr调用该函数:
shared_ptr<Derived> d = ...;
SomeFunction(d);
但这不起作用。如果我也使用普通指针(即隐式转换为Base *&amp; from Derived *),它不起作用。一种解决方法是从Derived中创建一个Base指针,然后将其传递给函数。
shared_ptr<Base> base = d;
SomeFunction(b);
但从编码的角度来看,这并不是很漂亮。它还增加了混乱和潜在的微妙错误:
shared_ptr<Derived> d = derived;
shared_ptr<Base> b = derived;
SomeFunction(b);
// b and d might now be pointing to different things -- not good!
有更好的方法吗?
答案 0 :(得分:2)
你要做的事情本质上是危险的,而C ++正在努力实现它的目的。考虑一下C ++是否允许您以您想要的方式调用SomeFunction
。然后你可以这样做:
struct Base {
};
struct Derived1 : Base {
void f1();
};
struct Derived2 : Base {
void f2();
};
void SomeFunction(shared_ptr<Base> &p)
{
p = make_shared<Derived2>(); // nothing wrong with converting
// a Derived2 pointer to a Base pointer.
}
int main()
{
shared_ptr<Derived1> d = make_shared<Derived1>();
SomeFunction(d); // An error, but what if it wasn't?
d->f1(); // Trying to call method f1 of a Derived2!
}
编译器无法知道d
从Derived1
指针变为Derived2
指针,因此它无法为您提供编译错误当您尝试调用f1
的方法Derived2
时。
答案 1 :(得分:1)
您可以模拟智能指针类型的功能
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
class Base {
public:
virtual void hello() {
cout << "hello base" << endl;
}
};
class Derived : public Base {
public:
void hello() {
cout << "hello derived" << endl;
}
};
class otherClass {
public:
};
template<typename T>
void SomeFunction(shared_ptr<T> &base_ptr)
{
static_assert(is_base_of<Base, T>::value == true, "Wrong non-derived type");
base_ptr->hello();
// Rebase it
base_ptr.reset(new Derived);
base_ptr->hello();
}
int main() {
shared_ptr<Base> obj(new Base());
SomeFunction(obj);
// hello base
// hello derived
shared_ptr<Derived> obj2(new Derived());
// hello derived
// hello derived
SomeFunction(obj2);
shared_ptr<otherClass> obj3(new otherClass());
SomeFunction(obj3); // ASSERT
return 0;
}
如果您打算在重置智能指针时更新所有智能指针,您将不得不自己做一些簿记,因为它们不是设计为具有“类似信号”的机制来通知其他指向智能指针同一个对象。
如果您打算将它与Base和相关子类一起使用,请编辑我的答案以提供编译时安全性。
警告:上面的解决方案使用C ++ 11 ,在C ++ 11之前的代码中也可以用类似的方式完成相同的操作