-1

I've tried to use c++ properties and now I'm stuck with this:

class a {
    protected:
        // wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
        template<class s, typename t>
        class getonly {
            protected:
                friend s;
                t value;
                t set(); // operator =...
            public:
                t get(); // t operator...
        };
};

class b : public a {
    public:
        getonly<b, int> id;
};

What I want is something like this, where getonly is parametrized by only the typename (int), and not the class (b):

class b : public a {
    public:
        getonly<int> id;
};

Is this possible? Can anyone help me?

jpaugh
  • 6,634
  • 4
  • 38
  • 90
Lê Tuấn
  • 13
  • 3
  • 5
    what you want to achieve? – AADProgramming Jul 25 '15 at 02:31
  • i want class a::template class getonly { ... } – Lê Tuấn Jul 25 '15 at 02:42
  • 1
    See this: template That means that getonly needs to be specified with 2 template parameters, so no you cant –  Jul 25 '15 at 03:16
  • i wrote it. and it need to be improved – Lê Tuấn Jul 25 '15 at 03:20
  • 1
    switch between class s and typename t and set a default class s = b. In other word: template, now you can do getonly id; as long as the second parameter is b. –  Jul 25 '15 at 03:22
  • how do I do that? can you write down some line of code. I cant translate English to C easy – Lê Tuấn Jul 25 '15 at 03:31
  • i will have class c, d, e, f... inherit class a or b or third level class and still using getonly class – Lê Tuấn Jul 25 '15 at 03:34
  • then no, what you are asking for can't be accomplished since the type of the class needs to be known at compile time. You can't use typeinfo since its at runtime and the 'this' keyword can't be used outside of functions. –  Jul 25 '15 at 04:41
  • Wikipedia lies: this approach doesn't "emulate properties" at all, because it fails to have one of the most important parts of properties: that you can change your mind later and make `foo.id` be the result of a function call rather than accessing a data member. –  Jul 25 '15 at 13:09
  • You misunderstood the point of @AADTechnical's comment: this looks like an example of the XY problem: you want to do X, and think that you can do X with Y. Then you have trouble with Y, so you come here to ask for help with Y. It would be much more useful if you asked X here instead. –  Jul 25 '15 at 13:13
  • Thanks everyone for support! I apologize for not being word-perfect in English and my question is not clear. – Lê Tuấn Jul 27 '15 at 01:11
  • Hello, and welcome to [so]! I edited your question to describe your code with English. Please note: from what I can tell, your question is more about `generics` and type parameters that it is about properties, and my edit reflects this. (Maybe this will help you find more relevant answers or comments.) – jpaugh Jul 27 '15 at 02:53

2 Answers2

1

It appears that you want a data member that can be read by any code, but that can only be changed by the containing class.

The attempt at providing friend-ship via template would not have compiled prior to C++11. It means that this code can not be easily modified to work with a C++03 compiler (with C++03 one could express the access restriction on modification via e.g. an owner credential argument to a setter). However, that concern becomes less significant every day.

Here's your code modified to compile, and with the inheritance changed from public to private (it doesn't make much sense to say that b "is-an" a):

class a {
protected:
    // wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
    template<class s, typename t>
    class getonly {
    protected:
        friend s;
        t value_;
    public:
        auto get() const -> t const& { return value_; }
        operator t const& () const { return value_; }

        getonly( t v ): value_( v ) {}
    };
};

class b : private a {
public:
    getonly<b, int> id;

    void set_id( int x ) { id.value_ = 2*x; }

    b(): id( 42 ) {}
};

#include <iostream>
auto main() -> int
{
    using namespace std;
    b obj;
    cout << obj.id << endl;
    obj.set_id( 333 );
    cout << obj.id << endl;
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

So first off, this can be done with CRTP

template<typename s>
class a {
protected:
    // wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
    template<typename t>
    class getonly {
    protected:
        friend s;
        t value;
        t set(); // operator =...
    public:
        t get(); // t operator...
    };
};

class b : public a<b> {
public:
    getonly<int> id;
};

But since you mentioned inheritance, are you aware that friend declarations are not inherited? If that is your goal, then there is a more elegant solution - do not use the property as a base class but as traits:

template<typename T, typename F>
class property_impl
{
    friend F;
private:
    T value_;

protected:
    void set(T value)
    {
        value_ = value;
    }

public:
    T get()
    {
        return value_;
    }
};

template<typename F>
class property_traits
{
    template<typename T> using property = property_impl < T, F > ;
};

class foo : public property_traits < foo >
{
public:
    property<int> id_;
};

class bar : public foo, public property_traits < bar >
{
public:
    property<int> another_id_;

    void doStuff(foo f)
    {
        auto value =  f.id_.get();
        // f.id_.set(5); <-- fails since friend is not inherited

    }
};

int main(int argc, char** argv)
{
    foo f;
    auto value = f.id_.get();
    bar b;
    auto another_value = b.another_id_.get();
    b.doStuff(f);
    return 0;
}

This will give you the ability to inherit and specialize on each class that needs a property while retianing the fact, that only the class type used in specialization is able to modify the value.

Again, maybe you want that, I am not sure.

Rudolfs Bundulis
  • 11,636
  • 6
  • 33
  • 71
  • Thank you. But, i've tried it before and when I have class c inherit class b it not work – Lê Tuấn Jul 26 '15 at 16:59
  • @LêTuấn can you post your example? I tried to show in my code with `bar` that you can inherit `foo` and have a property for `bar` too - if that is not what you want, can you then show what is that you are trying to achieve? – Rudolfs Bundulis Jul 27 '15 at 08:40