0

I have a class that contains a pointer. I want to keep the user of the class from accessing the address of the pointer (so they can't set it to another address, delete it, or what-not). However, I would like the user to be able to modify the pointer data (or member data if it's not POD) as well as call the pointer's methods (assuming it has any).

Is there any way of returning a pointer or reference that allows you to change the data that a pointer points to without being able to change the pointer value itself?

So:

class A
{
public:
    int Value;
    void Method();
};

class Wrapper
{
public:
    Wrapper()
    {
        Pointer = new A;
    }
    // Method that somehow would give access to the object without 
    // Allowing the caller to access the actual address
    A* GetPointer()
    {
        return Pointer;
    }

private:
    A* Pointer;
};

int main()
{
    Wrapper foo;

    foo.GetPointer()->Value = 12; // Allowed
    foo.GetPointer()->Method();   // Allowed
    A* ptr = foo.GetPointer();    // NOT Allowed
    delete foo.GetPointer();      // NOT Allowed

    return 0;
}

I realize I could modify member data with getters and setters, but I'm not sure what to do about the methods (pass a method pointer maybe?) and I'd like to know if there is a better way before I accept a solution that I personally think looks messy.

  • 1
    Well, modifying it with getters and setters, which you mention, are the whole point of encapsulating private data, which sounds like what you're trying to do... that is, allow access to and updating of a value, but retaining and managing control over that data within your class. – David Hoelzer Jan 13 '16 at 05:38
  • Exactly, I'm just not sure about calling a method of an encapsulated object, whether I have to pass in a method pointer to a function that calls it internally or if there is some other, better method. – JubileeTheBear Jan 13 '16 at 05:43
  • *I want to keep the user of the class from accessing the address of the pointer* -- Why does `Pointer` need to be a pointer? Why not just have an `A` object as a member? Then there is nothing to `delete` or change the address of. – PaulMcKenzie Jan 13 '16 at 05:57
  • I question your need to allow `foo.GetPointer()->Value = 12;` but disallow `A* ptr = foo.GetPointer();`. It's not clear what you are trying to protect. Remember that a determined programmer can sabotage your carefully designed access controls. – R Sahu Jan 13 '16 at 06:09
  • @PaulMcKenzie I'm expecting the Wrapper class to hold shared data, so that forces me to use pointers. – JubileeTheBear Jan 13 '16 at 06:21
  • Since a "Reference is its referent" AKA what it refers to cannot be changed, would that help you at all? – Trés DuBiel Jan 13 '16 at 06:23
  • @RSahu The idea is to allow modification of the *data* the pointer is pointing at, while keeping the pointer *address* from being changeable. Though now that I think about it, calling 'delete' on the pointer would technically be modifying the data and not the address, so maybe I am going about this wrong. – JubileeTheBear Jan 13 '16 at 06:24
  • Just tell your users that the pointer must not be `delete`d. If they don't listen, it's their fault. In C++, nobody stops you from invoking undefined behavior by writing `int i; delete &i;` and the like. Did you ever accidentally write `delete std::make_shared().get();`? And as long as the pointer member is `private` and you only grant access to it by `return`ing *a copy of the pointer value*, nobody will be confused to re-assign it. – 5gon12eder Jan 13 '16 at 06:27
  • @TrésDuBiel A reference may work. I don't think I'd be able to convert `A* Pointer` to `A& Reference` though since there will be times where I reset the pointer, but I might be able to find a work around using references (maybe create a whole new object or something when copying?). – JubileeTheBear Jan 13 '16 at 06:31
  • 1
    @5gon12eder I was afraid of that. I had been trying to "child-proof" my code so much that I forgot that C++ coder's are *C++* coders ***because*** they aren't children. – JubileeTheBear Jan 13 '16 at 06:36
  • @JubileeTheBear As a general rule I recommend instead of trying to disable all the ways your code shouldn't be used, try to make _the way it should be used_ as obvious as possible. – Fiktik Jan 13 '16 at 07:08
  • http://stackoverflow.com/questions/23998242/accessing-private-members-of-a-struct-using-offset-of-member-variables – Joel Cornett Jan 13 '16 at 07:28
  • For the delete part, you could always make the destructor of `A` non-public. – Joel Cornett Jan 13 '16 at 07:31

2 Answers2

1

It's not possible. The whole reason why ->Value is legal is because the expression to the left is a (smart) pointer to A*.

Obviously, with a non-smart pointer you already have your A* right there. Since raw pointers are not user-defined types, you cannot mess with the overload resolution.

With a smart pointer, (*ptr).Value has to work. That means you have to return a A& from operator* which in turn means that &(*ptr) gets you the traw pointer from a smart pointer.

There's even std::addressof for classes that try to block operator&.

MSalters
  • 173,980
  • 10
  • 155
  • 350
-1

You could make a getter That returns a reference to the object, ex:

A &GetObject()
{
    return *Pointer;
}

This allows full access to the pointed-to object without providing access to the pointer itself at all.

Extrarius
  • 154
  • 1
  • 8
  • 1
    And if I do `A* foo = &x.GetObject()`? – Joel Cornett Jan 13 '16 at 07:25
  • You are answering the question as it is asked, but that is not what JubileeTheBear means. By returning a reference, you are effectively giving the caller a copy of the pointer, so that the caller cannot modify the owner's original pointer, BUT JubileeTheBear wants to prevent the caller from being able to call `delete` (which you can still do on a copy of the pointer). What JubileeTheBear actually wants, is a way to let the caller modify an object without knowing where it resides in memory, which isn't possible. – Pianosaurus Jan 13 '16 at 08:12