我目前正在开发自己的小框架,它具有以下设计模式: 每个对象都继承自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参数列表末尾传递的默认值。 所以我的问题:
我想为我的小框架创建一个容器类,尽可能少地实现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);
}
答案 0 :(得分:1)
std::vector::push_back
无法获取其他参数。
我的建议:
使用合成代替std::vector
的继承来定义LContainer
。
class LContainer : public LObject
{
LContainer(LObject* const _pParent) : LObject(_pParent)
{
}
// Member variable
std::vector<LObject*> containedObjects_;
};
在LContainer
中添加一项功能以添加对象。在此函数中,使用std::vector::push_back
然后执行必要的其他处理。
class LContainer : public LObject
{
LContainer(LObject* const _pParent) : LObject(_pParent)
{
}
void addObject(LObject* object)
{
containedObjects_.push_back(object);
// Do the additional processing.
// ...
//
}
// Member variable
std::vector<LObject*> containedObjects_;
};
答案 1 :(得分:0)
我找到的最佳解决方案是继承LObject和std :: vector,并重新实现了向向量添加内容的一些函数。
std :: vector的功能是使用关键字using。
注意:私有继承用于阻止用户键入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(this->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);
}