0

I am deriving stl container class vector and trying to overload the [] operators to provide range checking on accessing element with subscript. But I get compile errors when try to create const object of my derived class Vec.

For example below is the code:

template<class T>
class Vec : public vector<T>
{
    public:
    Vec(): vector<T>()
    {
    }
    Vec(int i):vector<T>(i)
    {
    }
    T& operator[](int i)
    {
        return at(i);
    }
    const T& operator[](int i) const
    {
       if(i>=size())
       cout<<"error"<<endl;
       return at(i);
    } 
};

void main()
{
    Vec<int> v1(10); //works fine
    const Vec<int> v(10); //error                                
}

Why the code const vector v(10); works but const Vec v1(10); doesn't work. Is there something I am missing? Why am I not able to create const object?

Vinod
  • 115
  • 11
  • 1
    Do us a favor and post your *real* code. The error your describing, if it is in this posting, is dwarfed by the numerous other errors. – WhozCraig Apr 01 '16 at 20:39
  • 2
    I am unfortunately unable to reproduce your problem with g++ 4.5 (after fixing issues like `void main`, missing includes, and not qualifying non-dependent names with `this->`). Can you please offer any further clarification to help us? – Mark B Apr 01 '16 at 20:39
  • @MarkB ditto that. – WhozCraig Apr 01 '16 at 20:41
  • The code as posted compiles without errors for me in Visual Studio 2005. What compiler are you using? – Dan Korn Apr 01 '16 at 20:47

2 Answers2

0

The STL classes like std::vector are generally not meant to be derived from.

But the code works correctly like this:

template<class T>
class Vec : public vector<T>
{
    public:
    Vec(): vector<T>()
    {
    }
    Vec(int i):vector<T>(i)
    {
    }
    T& operator[](int i)
    {
        return vector<T>::at(i);
    }
    const T& operator[](int i) const
    {
       if(i>=vector<T>::size())
       cout<<"error"<<endl;
       return vector<T>::at(i);
    } 
};

int main()
{
    Vec<int> v1(10); //works fine
    const Vec<int> v(10); //error                                
    v1.push_back(5);
    v1.push_back(6);
    int i = v1[3];
}

The functions at and size from the base std::vector need to be called with using either vector<T>::at(i) or this->at(i). This is always true when the base class is a template: Then "vector<T>" is a dependent name (its meaning depends on the template argument T), and in that case its members are not automatically exported to the scope of the Vec class definition.

Also cout<"error" must be cout<<"error", and main must return an int.

const does not pose a problem in this case.

In general, push_back cannot be used on a const std::vector, because it modifies the vector. But copy initialization or list initialization can be used to create a non-empty const std::vector. For example

const std::vector<int> vec {1, 2, 3};
tmlen
  • 8,533
  • 5
  • 31
  • 84
0

Bjarne Stroustrup covers this issue in "A Tour of C++".

template<typename T>
class Vec : public std::vector<T> {
public:
    using vector<T>::vector;      // use the constructors from vector (under the name Vec)

    T& operator[](int i)
    { return vector<T>::at(i); }

    const T& operator[](int i) const
    { return vector<T>::at(i); }
}

"Vec inherits everything from vector except for the subscript operations that it redefines to do range checking."

user515430
  • 298
  • 1
  • 3
  • 7