0

I am trying to overload my operator-> for a handle class to return const and non const pointer, pointing towards a base class.

Looking at the code i posted, in the trial function, if i add in the const keyword, the error message will be

||=== Build: Debug in Const trial (compiler: GNU GCC Compiler) ===|
C:\Const trial\main.cpp
||In function 'bool trial(Cards_pointer)':|
C:\Const trial\main.cpp|50|error: passing 'const Cards_pointer' as 'this' argument of 'Cards*& Cards_pointer::operator->()' discards qualifiers [-fpermissive]|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

My question is whether it is possible to do so, if yes, may i know what is the correct implementation?

#include <iostream>
#include<vector>
#include<stdexcept>
#include<algorithm>
using namespace std;

class Cards
{
private:
    int x;
public:
    Cards():x(3) {}
    int rx()const
    {
        return x;
    }
};

class Cards_pointer
{
private:
    Cards* cp;
    size_t* refptr;

public:
//default constructor
    Cards_pointer():cp(0),refptr(new size_t(1)) {}
    Cards_pointer(Cards*t):cp(t),refptr(new size_t(1)) {}
//copy constructor
    Cards_pointer (const Cards_pointer&s):cp(s.cp),refptr(s.refptr)
    {
        refptr=s.refptr;
        cp=s.cp;
//++*refptr;
        *refptr=*refptr+1;
    }

    Cards*&operator->()
    {
        if(cp)
            return cp;

        else throw std::runtime_error("uninitialized Cards");
    }

};

bool trial(const Cards_pointer x)
{
    if(x->rx()==3)
        return true;

    return false;
}

int main()
{
    Cards_pointer x=new Cards();

    bool cond=trial(x);

}
user207421
  • 305,947
  • 44
  • 307
  • 483
Esther
  • 47
  • 3
  • Note that usually `operator->` returns pointer, not a reference to a pointer. – juanchopanza Aug 28 '17 at 06:24
  • So does it means i have to define another operator to return a const pointer? – Esther Aug 28 '17 at 06:27
  • Yes, but you'd have to do it anyway. – juanchopanza Aug 28 '17 at 06:32
  • 1
    That is, if the "handled" object is conceptually part of the handle class. i.e. does modifying the handled object mean modifying the handle? This is a design choice. If the answer is no, then you just need `Cards* operator->() const`. If yes, you need two operators. – juanchopanza Aug 28 '17 at 06:34

2 Answers2

1

Just return a pointer to const and provide a const qualified overload

class Something {
public:
    void bar() {}
    void foo() const {}
};

class Wrapper {
public:
    Something* operator->() {
        return &this->something;
    }
    const Something* operator->() const {
        return &this->something;
    }
private:
    Something something;
};

int main() {
    const auto c_wrapper = Wrapper{};
    c_wrapper->foo();
    // The below is an error
    // c_wrapper->bar();
    auto m_wrapper = Wrapper{};
    m_wrapper->bar();
}

If you are worried about duplicated code in the const and non const overloads see Const function calling non const or vice versa (to avoid duplication)?

Curious
  • 20,870
  • 8
  • 61
  • 146
  • Hey, i have actually tried a similar function, however mine did not work because i added & in between Something* and operator-> for the const version.. May i know why does that lead to an error? The error message is as below C:\Const trial 2\main.cpp|18|error: invalid initialization of reference of type 'const Something*&' from expression of type 'Something* const'| – Esther Aug 28 '17 at 06:50
  • Wrapper wraps a non-pointer. The example doesn't translate to smart pointers, which is what `Cards_pointer` meant to be. – n. m. could be an AI Aug 28 '17 at 06:53
  • @Esther I'm guessing thats the same reason this causes an error https://wandbox.org/permlink/Zi6o2PfpOSACKLq6 – Curious Aug 28 '17 at 06:55
0

If you overload your operator->, the behaviour will not mimick that of built-in pointers (and will not make much sense at all).

Built-in pointers come in two flavours: pointers and pointers-to-const. (We ignore volatile here). These flavours are different types. Pointers themselves being const have nothing to do with constness of what they point to.

In order to imitate this behaviour, you need two flavours of Cards_pointer, one with operator-> that returns a normal pointer, and one with operator-> that returns a pointer-to-const.

  class Cards_pointer_base { ... };
  class Cards_pointer: private Cards_pointer_base {         
     public:
       // usual constructors/assignment operators
       using ...; // necessary members from the base
       Cards* operator->() { ... }
  };
  class Cards_const_pointer: private Cards_pointer_base {         
     public:
       // usual constructors/assignment operators
       using ...; // necessary members from the base
       const Cards* operator->() { ... }
       // conversions from pointer to non-const
       Cards_const_pointer(const Cards_pointer& from) { ... }
       Cards_const_pointer& operator=(const Cards_pointer& from) { ... }
  };

Standard smart pointers are class templates, so one can just write shared_ptr<Cards> and shared_ptr<const Cards>.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243