【发布时间】:2015-02-20 16:55:55
【问题描述】:
我目前正在开发自己的小框架,它具有以下设计模式: 每个对象都继承自 LObject 并有一个父对象,当对象发生变化时它会通知该父对象。 这是一个例子:
class LObject
{
public:
LObject(LObject* const _pParent = nullptr) :
_mpParent(_pParent),
_mChildrenCount(0)
{
if(parent() != nullptr)
_mChildId = parent()->GenerateChildId();
}
unsigned int id() const { return _mChildId; }
protected:
LObject* const parent() const { return _mpParent; }
unsigned int selfId() const { return -1; }
unsigned int GenerateChildId() const { return _mChildrenCount++; }
virtual void ChildChanged(unsigned int _childId)
{
if(parent() != nullptr)
parent()->ChildChanged(id());
}
virtual void ChildChanged() const
{
if(parent() != nullptr)
parent()->ChildChanged(id());
}
private:
LObject* const _mpParent;
unsigned int _mChildId;
mutable unsigned int _mChildrenCount;
};
template <typename T>
class LType : public LObject
{
public:
/// constructors
LType(LObject* const _pParent=nullptr) :
LObject(_pParent),
_mValue()
{}
LType(const T& _rcValue, LObject* const _pParent=nullptr) :
LObject(_pParent),
_mValue(_rcValue)
{}
/// template type
typedef T size_type;
/// modify data
void set(const T& _rcValue, bool _notifyParent=true)
{
_mValue = _rcValue;
if(_notifyParent)
ChildChanged();
}
void add(const T& _rcValue, bool _notifyParent=true); // same with +=
/// get data
const T& operator()() const; // returns _mValue
/// operators (modify / get data)
void operator=(const T& _rcValue); // same as set
private:
T _mValue;
};
class SomeObject : public LObject
{
public:
SomeObject(LObject* const _pParent = nullptr) :
LObject(_pParent),
someInt(this)
{}
LType<int> someInt;
virtual void ChildChanged(unsigned int _childId)
{
LObject::ChildChanged();
if(_childId == someInt.id())
std::cout << "someInt changed!" << std::endl;
}
};
int main(int argc, char* argv[])
{
SomeObject obj;
obj.someInt = 5;
return 0;
}
输出:someInt 改变了!
现在我想实现一个容器类,它应该像这样工作:
class SomeOtherObject : public LObject
{
public:
SomeOtherObject (LObject* const _pParent = nullptr) :
LObject(_pParent),
someContainer(this)
{}
LContainer<LType<int>> someContainer;
virtual void ChildChanged(unsigned int _childId)
{
LObject::ChildChanged();
if(_childId == someContainer.id())
std::cout << "someContainer changed!" << std::endl;
if(_childId == someContainer[0].id())
std::cout << "someContainer[0] changed!" << std::endl;
}
};
int main(int argc, char* argv[])
{
SomeOtherObject obj2;
obj.someContainer.push_back(5);
obj.someContainer[0].set(32);
return 0;
}
Depending on the implementation the output should be:
someContainer changed!
someContainer[0] changed!
or
someContainer changed!
someContainer changed!
(暂时我不关心容器的元素是否是容器的子元素,或者它们是否与容器具有相同的父元素。)
所以如您所见,我希望容器像 std::vector 一样工作,唯一的区别是,在其中创建的对象(使用 push_back 或使用 insert)知道它们的父对象,并且容器知道它是父对象。 (也许我什至不关心知道它是父容器的容器,但我认为这是强制性的) 在最好的情况下,我只想使用 std::vector。
我没有找到任何线索,比如在 cplusplus 参考中的 std::vector::push_back 参数列表末尾传递的默认值。 所以我的问题:
- 是一种方法,我只是没找到?
- 如果没有,有没有比完全重新实现 std::vector 更简单的方法?
我想要一个容器类用于我的小框架,尽可能少地实现 STL 中所有现有的方法。
我想这样实现它(如果可能的话)
class LContainer : public std::vector, public LObject
{
LContainer(LObject* const _pParent) :
LObject(_pParent)
{
std::vector::addValuesWithDefaultParameter(parent()); // If something like that is available)
}
};
编辑:这就是我解决问题的方法。
我继承了 LObject 和 std::vector 并重新实现了一些向向量添加内容的函数。
注意:私有继承用于防止用户输入obj.container.std::vector::push_back(element);
/// LContainer.h
template <typename T>
class LContainer : public LObject, std::vector<T>
{
public:
LContainer(LObject* const _pParent=nullptr);
LContainer(unsigned int _startSize, LObject* const _pParent=nullptr);
LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent=nullptr);
/// Iterators
using std::vector<T>::begin;
using std::vector<T>::end;
using std::vector<T>::rbegin;
using std::vector<T>::rend;
using std::vector<T>::cbegin;
using std::vector<T>::cend;
using std::vector<T>::crbegin;
using std::vector<T>::crend;
/// Capacity
using std::vector<T>::size;
using std::vector<T>::max_size;
void resize(unsigned int _newSize, const T& _rcValue);
using std::vector<T>::capacity;
using std::vector<T>::empty;
using std::vector<T>::reserve;
using std::vector<T>::shrink_to_fit;
/// Element access
using std::vector<T>::operator [];
using std::vector<T>::at;
using std::vector<T>::front;
using std::vector<T>::back;
/// add elements
void assign(unsigned int _count, const T& _rcValue);
void push_back(const T& _rcValue);
using std::vector<T>::pop_back;
void insert(unsigned int _position, const T& _rcValue);
void insert(unsigned int _position, unsigned int _count, const T& _rcValue);
using std::vector<T>::erase;
using std::vector<T>::swap;
using std::vector<T>::clear;
using std::vector<T>::emplace;
using std::vector<T>::emplace_back;
/// Allocator
using std::vector<T>::get_allocator;
private:
T _mElementDummy;
};
/// LContainer.inl file
template <typename T>
LContainer<T>::LContainer(LObject* const _pParent) :
LObject(_pParent),
std::vector<T>(),
_mElementDummy(_pParent)
{}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, LObject* const _pParent) :
LObject(_pParent),
std::vector<T>(),
_mElementDummy(_pParent)
{
while(std::vector::size() < _startSize)
std::vector::push_back(_mElementDummy);
}
template <typename T>
LContainer<T>::LContainer(unsigned int _startSize, const T& _rcValue, LObject* const _pParent) :
LObject(_pParent),
std::vector<T>(),
_mElementDummy(_pParent)
{
_mElementDummy = _rcValue;
while(std::vector::size() < _startSize)
std::vector::push_back(_mElementDummy);
}
template <typename T>
void LContainer<T>::resize(unsigned int _newSize, const T& _rcValue)
{
_mElementDummy = _rcValue;
std::vector::resize(_mElementDummy, _mElementDummy);
}
template <typename T>
void LContainer<T>::assign(unsigned int _count, const T& _rcValue)
{
_mElementDummy = _rcValue;
std::vector::assign(_count, _mElementDummy);
}
template <typename T>
void LContainer<T>::push_back(const T& _rcValue)
{
_mElementDummy = _rcValue;
std::vector::push_back(_mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, const T& _rcValue)
{
_mElementDummy = _rcValue;
std::vector::insert(_position, _mElementDummy);
}
template <typename T>
void LContainer<T>::insert(unsigned int _position, unsigned int _count, const T& _rcValue)
{
_mElementDummy = _rcValue;
std::vector::insert(_position, _count, _mElementDummy);
}
【问题讨论】:
-
我不太明白你想要完成什么。也许您希望看到的一些示例代码会有所帮助。
-
最后添加了示例代码。
-
注意
_mChildId在parent() == nullptr时没有初始化。 -
@Jarod42 没关系,_mChildId 仅在父母可用时使用
-
@Gamer2015:它的 getter 可以从公共接口获得,所以用户可以使用它...
标签: c++ c++11 vector stl containers