一个棘手的问题。如果想编写一个将指针返回给某个IFoo
对象的函数,是否可以阻止指定该指针?
我不想让IFoo
成为单例,我可以隐藏或删除复制和赋值运算符,但C ++实际上是否允许使用模式,我明确地必须调用其他人来获取对象?
背景问题是:我正在考虑某种依赖容器,你应该总是要求容器得到一些IFoo *
(为了多态而指针)。用户永远不能将其保存到某个局部变量或成员,以避免对其进行停顿引用。 (对于指示容器不再返回Foo
的情况,该情况源自IFoo
但Bar
)
编辑以澄清,尽管用户R Sahu已经说过这是不可能的。 事实上,马克B的例子是我想要阻止的完美例证:
IFoo* foo_ptr_I_will_keep_forever = obj->getIFoo();
当我没有接口但只有显式的类型实例时,我可以返回一个引用,给定一个私有操作符=和copy ctor就足够了。
答案 0 :(得分:2)
给他们一个对象(他们可以存储,如果他们想要的话)总是通过私人(朋友)接口查找真实对象。
例如,IFooCaller
通过获取当前IFoo
并转发所有呼叫来实现IFoo
。
答案 1 :(得分:2)
你的标题是:
有没有办法阻止指针的分配?
不,如果函数返回指针,则无法阻止。
但是,如果返回一个句柄,该句柄可以是指向仅向前声明的类型的指针,也可以是可用于显示真实对象的整数值,并确保所有实际功能都适用于处理,然后你可以有更多的自由,当你可以删除真实对象,而没有留下客户端代码悬挂指针的风险。
这是一个演示概念的简单程序。
#include <iostream>
#include <set>
// Foo.h
struct Foo;
using FooHandle = Foo*;
FooHandle createFoo();
void fooFunction1(FooHandle h);
void fooFunction2(FooHandle h);
// Test Program
int main()
{
FooHandle h = createFoo();
fooFunction1(h);
fooFunction2(h);
fooFunction1(h);
return 0;
}
// Foo implementation.
namespace FooImpl
{
std::set<Foo*>& getLiveFooObjects()
{
static std::set<Foo*> liveObjects;
return liveObjects;
}
bool isValid(Foo* h)
{
return (getLiveFooObjects().find(h) != getLiveFooObjects().end());
}
}
using namespace FooImpl;
struct Foo {};
FooHandle createFoo()
{
FooHandle h = new Foo{};
getLiveFooObjects().insert(h);
return h;
}
void fooFunction1(FooHandle h)
{
if ( isValid(h) )
{
std::cout << "In fooFunction1.\n";
}
else
{
std::cout << "Ooops. The handle is no longer valid.\n";
}
}
void fooFunction2(FooHandle h)
{
std::cout << "In fooFunction2.\n";
delete h;
getLiveFooObjects().erase(h);
}
输出:
In fooFunction1.
In fooFunction2.
Ooops. The handle is no longer valid.
答案 2 :(得分:1)
一个中间答案,可以防止意外存储指向特定实现的指针,但不会阻止某人故意这样做:
template <typename T> class service_wrapper;
class service_manager
{
template <typename T> friend class service_wrapper;
public:
template <typename T>
service_wrapper<T> get() const;
private:
template <typename T>
T* get_instance() const;
};
template <typename T>
class service_wrapper
{
friend class service_manager;
public:
T* operator->() const;
private:
service_wrapper(service_manager const & p_sm) : sm(p_sm) { }
service_manager const & sm;
};
template <typename T>
T* service_wrapper<T>::operator->() const
{
return sm.get_instance<T>();
}
您的经理只会分发service_wrapper<T>
的实例。 operator->
实现允许使用wrapper->method(...);
调用服务,并始终从服务管理器获取实现指针。
这可以像:
一样被规避T *ptr = sm.get<T>().operator->();
但这不是你不小心做的事情。