-2

This is an excerpt of an implementation of a Stack class in C++:
Stackdemo.hpp

#include<iostream>

using namespace std;

template<typename T>
class Stack
{
    private:
        int top;
        T *arr;

    public:
        Stack(int size)
        {
            arr = new T[size];
            top = 0;
        }

        void push(const T &x)
        {
            arr[top++] = x;
        }

        int size()
        {
            return top;
        }

        friend ostream& operator<<(ostream &out, const Stack &s)
        {
            for(int i = 0; i < s.top; ++i) out<<s.arr[i]<<' '; // Works
            for(int i = 0; i < s.size(); ++i) out<<s.arr[i]<<' '; // Doesn't work

            return out;
        }
};

Here I am using a simple driver program to test it:
StackTest.cpp

#include<iostream>
#include"Stackdemo.hpp"

int main()
{
    Stack<int> S(5);

    S.push(1);
    S.push(2);
    S.push(3);

    cout<<S<<'\n';

    return 0;
}

My problem is in the operator overloading function: the first loop works and produces the expected output, but the second doesn't and gives an error "passing 'const Stack' as 'this' argument discards qualifiers [-fpermissive]". Obviously, I'd be using only one loop at a time. Why is there an issue, since size() just returns the value of top?

DimK
  • 301
  • 4
  • 16

2 Answers2

3

Your size() is non-const and because of this you cannot call it on a const Stack &s. As the method does actually not modify any members it should be declared as const anyhow :

int size() const {
    return top;
}

As a rule of thumb you can declare every member method as const and only if it needs to modify members remove the const.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • So when an object is passed as constant reference, it can't be used to call all of the class' functions, just those that are declared const? – DimK Mar 06 '18 at 12:17
  • 2
    Yes, of course. Because non-const member functions can modify the object, and you aren't allowed to do that if you have a const-reference. – Jonathan Wakely Mar 06 '18 at 12:19
  • 1
    @DimK314 exactly. Only methods declared as `const` are guaranteed to not modify the object, so it is only those that you can call on a `const` instance – 463035818_is_not_an_ai Mar 06 '18 at 12:19
  • OK, I see. So it doesn't matter that this specific function does not modify the object? – DimK Mar 06 '18 at 12:21
  • @DimK314 what do you mean? Yes it does matter, because if `size` would attempt to modify the object while it is declared as `const` you would get a compiler error. Try eg `int size() const { top+=2; return top; }` ... wont compile – 463035818_is_not_an_ai Mar 06 '18 at 12:35
  • 1
    @DimK314 I think now I get your last comment... no the compiler cannot decide on its own that a method does not modify the instance and then allow to call it on a const instance. You need to specifiy wether the method works on `const` instances or not – 463035818_is_not_an_ai Mar 06 '18 at 12:47
2

Declare the member function size like a constant member function

    int size() const
    {
        return top;
    }

because in the operator << there is used a constant reference to the object of the type Stack.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335