简体   繁体   中英

Can I initialize elements with an additional default-parameter using std::vector?

I'm currently working on my own little framework which has the following design pattern: Each object inherits from LObject and has a parent which it informs when something has changed in the object. Here's an example:

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;
}

Output: someInt changed!

Now I want to implement a container class, which should work like this:

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!

(For the time being i don't care if the elements of the container are children of the container or if they have the same parent as the container.)

So as you see I want the container to work like std::vector, the only difference is, that objects that are created in there (with push_back or with insert) know their parent and that the container knows it's parent. (Maybe I don't even care about the container knowing it's parent but I think it's mandatory) In the best-case scenario I'd like to just use std::vector.

I didn't find any clues of a feature like a default value that's passed at the end of the std::vector::push_back parameter list in the cplusplus reference. So my Questions:

  • Is a way and I just didn't find it?
  • if no, is there an easier way than completely reimplementing std::vector?

I want a container class for my little framework with as little implementations of allready existing methods from the STL as possible.

I'd like to implement it like that (if at all possible)

class LContainer : public std::vector, public LObject
{
    LContainer(LObject* const _pParent) :
        LObject(_pParent)
    {
        std::vector::addValuesWithDefaultParameter(parent()); // If something like that is available)
    }
};

Edit: This is how i solved the problem. I inherited from both LObject and std::vector and reimplemented the few functions that added something to the vector. Notice: private inheritance is used to prevent users from typing 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);
}

std::vector::push_back does not have the ability to take an additional parameter.

My suggestion:

  1. Use composition instead of inheritance from std::vector to define LContainer .

     class LContainer : public LObject { LContainer(LObject* const _pParent) : LObject(_pParent) { } // Member variable std::vector<LObject*> containedObjects_; }; 
  2. Add a function in LContainer to add objects. In this function, use std::vector::push_back and then do the necessary additional processing.

     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_; }; 

The best solution I found was to inherit from both LObject and std::vector and reimplemented the few functions that added something to the vector.

Functionality from std::vector was taken with the keyword using.

Notice: private inheritance is used to prevent users from typing 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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM