1

Hi I am trying to make some public member variables read only. I know I could do something like:

private: int _x;
public: const int& x;
Constructor(): x(_x) {}


I'm looking for something more manageable and easier to read. I found several templates on the internet all of which do similar to what is described as a proxy class in this SO answer.

I'm trying to adapt that proxy class so that I can put the template in an include and write something like this for each variable in a class that I need read only variables in:

public: proxy<int, myClass> num;

Even easier would be if I didn't have to say the class name every time but I don't know a way to get around that unless the class name is identified in the template.

I tried this in Visual Studio 2010 but it doesn't work, does anyone know why?

template <class T, class C>
class proxy {
    friend class C;
private:
    T data;
    T operator=(const T& arg) { data = arg; return data; }
public:
    operator const T&() const { return data; }
};

class myClass {
public:
    proxy<int,myClass> x;

public:
    void f(int i) {
        x = i;
    }
};

Thanks

Edit- Someone asked for what I mean by doesn't work:

int main(int argc, char **argv)
{
    myClass test;
    test.f(12);
    cout << test.x << endl;
    return 0;
}

returns:

b.cpp(122) : error C2649: 'typename' : is not a 'class'
        b.cpp(128) : see reference to class template instantiation 'proxy<T,C>'
being compiled
b.cpp(136) : error C2248: 'proxy<T,C>::operator =' : cannot access private membe
r declared in class 'proxy<T,C>'
        with
        [
            T=int,
            C=myClass
        ]
        b.cpp(125) : see declaration of 'proxy<T,C>::operator ='
        with
        [
            T=int,
            C=myClass
        ]
Community
  • 1
  • 1
loop
  • 3,460
  • 5
  • 34
  • 57
  • 6
    So you're saying templates are more manageable and easier to read than `const`? – Luchian Grigore Sep 02 '12 at 19:52
  • Tell us what "it doesn't work" means – Drew Dormann Sep 02 '12 at 19:56
  • @Luchian Not at all. I need something that's publicly read-only and privately doesn't have those same restrictions. `const` is great it's just not what I'm looking for here. If I use the former, in all my class functions I have to append a prefix and there are a lot of variables to do that with. It just makes for uglier code, I think. – loop Sep 02 '12 at 19:57
  • @Drew ok I updated my question to show the output from CL – loop Sep 02 '12 at 20:01
  • @test - That's helpful. The error messages are telling you that you have specific problems on lines 122, 128, and 136. Can you comment in which lines those are? – Drew Dormann Sep 02 '12 at 20:08
  • @Drew 122: `friend class C;`, 128: closing brace of proxy class, 136: `x = i;`. I think it doesn't like `friend class C` but I don't understand why not. If I do it the way described in the answer I linked it works, but then I'd have to c&p the template into each class. – loop Sep 02 '12 at 20:12
  • Tell why not private member variable and public getter function instead of this annoying stuff? Any particular reason? `class A { private: int x; public: int getX() const { return x; } };` – PiotrNycz Sep 02 '12 at 20:28
  • @Piotr the myClass I posted above is a very simple example. I have dozens of variables and I want to write `test.x` rather than `test.getX()` for each variable. It seems harder to work with over many variables, although I haven't tried it that way I so I don't know for sure. – loop Sep 02 '12 at 20:31
  • @test - understood. You accepted proper answer - good luck, – PiotrNycz Sep 02 '12 at 20:35

2 Answers2

4

Change this:

template <class T, class C>
class proxy {
  friend class C;

to this:

template <class T, class C>
class proxy {
   friend C;

Because C is a template parameter, it's not guaranteed that C will necessarily be a class type.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • That works thanks. I just tried proxying some string variables and I noticed if I have something like `proxy str` and I try to pass str to a function that takes a string reference the compiler will error with `cannot convert parameter 1 from 'proxy' to 'std::string &'`. Do you know what I'm doing wrong there? – loop Sep 02 '12 at 20:28
  • @test: you want a private non-const `operator T&() { return data; }` in the `proxy` class template to allow `myClass` to cast proxies to non-const references to `T`. – Oktalist Sep 02 '12 at 20:31
  • @Oktalist I tried that but then I can no longer access test.x in public: `error C2248: 'proxy::operator int &' : cannot access private member declared in class 'proxy'` – loop Sep 02 '12 at 21:40
0

I think that your problem is in design. You don't need a "public" members which is the encapsulation violation. I think that you are looking for something like IoC, take a look on visitor pattern it could help you:

class IStateHandler{
public:
  virtual void handleState( const proxy<int, myClass>& num )=0;
  virtual ~IStateHandler(){}
};

class myClass {
private:
    proxy<int,myClass> x;

public:
    void f(int i) {
        x = i;
    }

    void handleState( IStateHandler* stateHandler ){
       stateHandler->handle( x );
    }

};
AlexTheo
  • 4,004
  • 1
  • 21
  • 35