【发布时间】:2018-07-27 06:20:24
【问题描述】:
假设我有一个类 'Car' 有一个复杂的子类树。每个类都有一个唯一的 id。我有一个管理类,它跟踪所有汽车的指针,并可以根据id 查找它们。
class Car {
public:
using CarId = size_t;
Car* getCar(CarId id) const { return sMap[id]; }
Car(){
sMutex.lock();
mId = ++sLastId;
sMap.insert(pair(mId,this));
sMutex.unlock();
}
private:
static map<CarId,Car*> sMap;
static CarId sLastId;
static mutex sMutex;
CarId mId;
}
我想对此进行重构,以便 Car::getCar 返回 weak_ptr<Car>,因为返回原始指针会导致很多问题。
但是,要以一种天真的方式从构造函数将指向自身的弱指针添加到sMap 中,需要创建一个共享指针,它会在对象超出范围时立即销毁它:
sMutex.lock();
mId = ++sLastId;
sMap.insert(
pair(mId,
weak_ptr<Car>(shared_ptr(this))
)
);
sMutex.unlock();
该死,我想我需要使用一些工厂:
class CarFactory {
public:
shared_ptr<Car> createCar(){
sMutex.lock();
mId = ++sLastId;
auto res = shared_ptr<Car>(this);
sMap.insert(
pair(mId,
weak_ptr<Car>(res)
)
);
sMutex.unlock();
return result;
}
private:
map<CarId,Car*> sMap;
CarId sLastId;
mutex sMutex;
}
很好,但是有很多派生类,很多时候在我不能从这里包含的模块中,所以我不能为这里定义的每个可能的 Car 派生类型都有一个工厂方法,这将是非常不切实际的。但是我需要跟踪每辆汽车,我不能允许任何不通过工厂方法创建派生汽车的方法。
迄今为止我想出的最佳解决方案:
class CarFactory {
...
template<class DT, class Tp>
shared_ptr<DT> create(Tp params...)
{
sMutex.lock();
mId = ++sLastId;
auto res = shared_ptr<Car>(new DT(forward(params)...) );
sMap.insert(
pair(mId,
weak_ptr<Car>(res)
)
);
sMutex.unlock();
return result;
}
...
}
允许将派生类构造函数私有化:
class VolksWagenGolf : public VolksWagen {
friend class CarFactory;
private:
VolksWagen(bool enableEmissionCheat);
}
因此我只能按如下方式创建它:
shared_ptr<Car> myCar = CarFactory::create<VolksWagenGolf>(true);
是的,但我还是不喜欢它,因为:
- 它是一个模板,出于各种原因,最好不使用模板。
- 任何时候,不知道这种机制的同事都可以像以前那样使用公共构造函数来声明新的 Car 类型。但是现在当他使用那个公共构造函数时,他的汽车将不会被跟踪。
因此,如果您有任何想法如何实现这样一种模式,即每个派生类都必须通过集中记账机制创建,同时使用弱指针进行跟踪,请告诉我。
【问题讨论】:
-
将
Cars 构造函数设为私有,将CarFactory::create设为friend可以解决问题2。 -
但是如果我将 Car 的构造函数设为私有,那我根本不能继承它,不是吗?
-
你是对的。那是一个大脑放屁。
标签: c++ c++11 refactoring