Properties with non standard C++ (REALLY SORRY ABOUT THAT)

Discussion in 'C++' started by Vincent RICHOMME, Feb 15, 2007.

  1. Hi,

    first I would like to apologize about my question because usually I hate
    specific implementation but in this case I really would like an answer.
    Besides my example is an example of what's not to be done but I am aware
    of that.
    Don't loose time tell me that I should use standard implementation and
    consider my question as theoretical.
    So I am using Microsoft compiler and I have a class with lots of methods
    with get and set :


    class foo
    {
    public:
    ....

    LPCTSTR GetName();
    void SetName(LPCTSTR Value);
    A GetABC();

    void SetABC(A Value);
    A GetABC();

    void SetDEF(B Value);
    B GetDEF();

    ....

    };

    So I would like to mix preprocessor tricks(it's bad I know) and template :
    I am thinkinf of something like :


    DECLARE_PROPERTY(Name, LPCTSTR);
    DECLARE_PROPERTY(ABC, A);
    DECLARE_PROPERTY(DEF, B);


    and after maybe
    Property.Name = L"Vincent";
    LPCTSTR tszName = Property.Name;




    And here is what I have done for now :

    template<class TYPE>
    struct Property
    {
    TYPE m_Type;

    TYPE Get()
    {
    g_pClient->Get ...( m_Type); // FILL BY MACRO
    return TYPE;
    }

    void Set()
    {
    g_pClient->Set ...( m_Type); // FILL BY MACRO

    }

    __declspec(property(get = Get, put = Put)) TYPE the_prop;
    };

    // template specialization for C strings
    template<>
    struct Property<LPCTSTR>
    {
    ... blabla
    }..




    I am sur there is something to do with all that but I still cannot find
    the way.


    I would try something like

    DECLARE_PROPERTY(PropName, TYPE) \
    template<class TYPE> \
    struct Property \
    { \
    TYPE m_Type; \
    TYPE Get() \
    { \
    g_pClient->Get ...( m_Type); \
    return TYPE; \
    } \

    void Set() \
    { \
    g_pClient->Set ...( m_Type); \
    } \
    __declspec(property(get = Get, put = Put)) TYPE PropName; \
    }; \

    typedef something ...


    Please give me your feedback


    //------------------------ MS property ---------------------//
    / declspec_property.cpp
    struct S {
    int i;
    void putprop(int j) {
    i = j;
    }

    int getprop() {
    return i;
    }

    __declspec(property(get = getprop, put = putprop)) int the_prop;
    };

    int main() {
    S s;
    s.the_prop = 5;
    return s.the_prop;
    }
     
    Vincent RICHOMME, Feb 15, 2007
    #1
    1. Advertising

  2. Vincent RICHOMME wrote:
    > Hi,
    >
    > first I would like to apologize about my question because usually I
    > hate specific implementation but in this case I really would like an
    > answer. [..]


    Is there any reason why you dind't post it to the newsgroup that
    specifically caters to the needs of Visual Studio?

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 15, 2007
    #2
    1. Advertising

  3. Victor Bazarov a écrit :
    > Vincent RICHOMME wrote:
    >> Hi,
    >>
    >> first I would like to apologize about my question because usually I
    >> hate specific implementation but in this case I really would like an
    >> answer. [..]

    >
    > Is there any reason why you dind't post it to the newsgroup that
    > specifically caters to the needs of Visual Studio?
    >
    > V

    Yes and a good one : people here have better knowledge of C++ and are
    more used to manipulate concept like template, OOP.
    When I see people who can write boost class for instance, I must admit
    I am impressed and you cannot find people like that on any newsgroup.
     
    Vincent RICHOMME, Feb 15, 2007
    #3
  4. Vincent RICHOMME a écrit :
    > Victor Bazarov a écrit :
    >> Vincent RICHOMME wrote:
    >>> Hi,
    >>>
    >>> first I would like to apologize about my question because usually I
    >>> hate specific implementation but in this case I really would like an
    >>> answer. [..]

    >>
    >> Is there any reason why you dind't post it to the newsgroup that
    >> specifically caters to the needs of Visual Studio?
    >>
    >> V

    > Yes and a good one : people here have better knowledge of C++ and are
    > more used to manipulate concept like template, OOP.
    > When I see people who can write boost class for instance, I must admit
    > I am impressed and you cannot find people like that on any newsgroup.
    >

    But if you can give me a more standard approach I am curious.
    The problem here is my class has lots of methods with different names
    that almost do the same :

    class foo
    {
    public:
    ....

    LPCTSTR GetName();
    void SetName(LPCTSTR Value);
    A GetABC();

    void SetABC(A Value);
    A GetABC();

    void SetDEF(B Value);
    B GetDEF();

    ....
    };
     
    Vincent RICHOMME, Feb 15, 2007
    #4
  5. ok I found a solution to my problem.



    Vincent RICHOMME a écrit :
    > Vincent RICHOMME a écrit :
    >> Victor Bazarov a écrit :
    >>> Vincent RICHOMME wrote:
    >>>> Hi,
    >>>>
    >>>> first I would like to apologize about my question because usually I
    >>>> hate specific implementation but in this case I really would like an
    >>>> answer. [..]
    >>>
    >>> Is there any reason why you dind't post it to the newsgroup that
    >>> specifically caters to the needs of Visual Studio?
    >>>
    >>> V

    >> Yes and a good one : people here have better knowledge of C++ and are
    >> more used to manipulate concept like template, OOP.
    >> When I see people who can write boost class for instance, I must admit
    >> I am impressed and you cannot find people like that on any newsgroup.
    >>

    > But if you can give me a more standard approach I am curious.
    > The problem here is my class has lots of methods with different names
    > that almost do the same :
    >
    > class foo
    > {
    > public:
    > ...
    >
    > LPCTSTR GetName();
    > void SetName(LPCTSTR Value);
    > A GetABC();
    >
    > void SetABC(A Value);
    > A GetABC();
    >
    > void SetDEF(B Value);
    > B GetDEF();
    >
    > ...
    > };
     
    Vincent RICHOMME, Feb 15, 2007
    #5
  6. Vincent RICHOMME

    Ian Collins Guest

    Vincent RICHOMME wrote:
    > Hi,
    >
    > first I would like to apologize about my question because usually I hate
    > specific implementation but in this case I really would like an answer.
    > Besides my example is an example of what's not to be done but I am aware
    > of that.
    > Don't loose time tell me that I should use standard implementation and
    > consider my question as theoretical.
    > So I am using Microsoft compiler and I have a class with lots of methods
    > with get and set :
    >

    In most cases, getters and setters are a bad design smell. Why
    encapsulate something only to break the encapsulation?

    --
    Ian Collins.
     
    Ian Collins, Feb 15, 2007
    #6
  7. Vincent RICHOMME wrote:
    > Vincent RICHOMME a écrit :
    >> Victor Bazarov a écrit :
    >>> Vincent RICHOMME wrote:
    >>>> Hi,
    >>>>
    >>>> first I would like to apologize about my question because usually I
    >>>> hate specific implementation but in this case I really would like
    >>>> an answer. [..]
    >>>
    >>> Is there any reason why you dind't post it to the newsgroup that
    >>> specifically caters to the needs of Visual Studio?
    >>>
    >>> V

    >> Yes and a good one : people here have better knowledge of C++ and are
    >> more used to manipulate concept like template, OOP.
    >> When I see people who can write boost class for instance, I must
    >> admit I am impressed and you cannot find people like that on any
    >> newsgroup.

    > But if you can give me a more standard approach I am curious.
    > The problem here is my class has lots of methods with different names
    > that almost do the same :
    >
    > class foo
    > {
    > public:
    > ...
    >
    > LPCTSTR GetName();
    > void SetName(LPCTSTR Value);
    > A GetABC();
    >
    > void SetABC(A Value);
    > A GetABC();
    >
    > void SetDEF(B Value);
    > B GetDEF();
    >
    > ...
    > };


    I don't know what to recommend you. There is no one "hard and fast"
    solution that would be good for all. In many cases separating the
    concepts (to reduce the individual number of "properties") is good
    enough a way to go:

    class hasName {
    whatevertypeyoulike name;
    public:
    LPCTSTR GetName() const;
    void SetName(LPCTSTR);
    };
    ...
    class foo : public hasName .... {
    ...
    };

    (yes

    Essentially this employs the "policy" technique (see Alexandrescu,
    "Modern C++ Design").

    You can also create (and possibly pre-fill) a 'std::map' of all the
    named values of your "properties". You then have a slightly smaller
    set of functions:

    class foo {
    public:
    boost::any GetProp(LPCTSTR) const;
    void SetProp(LPCTSTR, boost::any);
    };

    There are plenty of other portable solutions, you just need to
    search for them. Have you actually tried looking, say, on Google?

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 15, 2007
    #7
  8. Vincent RICHOMME

    Jerry Coffin Guest

    In article <45d4d59d$0$19026$>,
    says...
    > Hi,
    >
    > first I would like to apologize about my question because usually I hate
    > specific implementation but in this case I really would like an answer.
    > Besides my example is an example of what's not to be done but I am aware
    > of that.
    > Don't loose time tell me that I should use standard implementation and
    > consider my question as theoretical.
    > So I am using Microsoft compiler and I have a class with lots of methods
    > with get and set :


    A design with lots of accessors and mutators is usually a sign of a
    problematic design -- you're usually better off fixing it than
    facilitating it. In particular, this usually signals somebody who's
    heard that public variables are bad, but hasn't grasped _why_ they're
    bad, so he makes the variables themselves private, then then provides
    public access to them via the get and set methods. The result is the
    worst of all worlds -- the design is still one of public variables, and
    all that's really changed is that the syntax has gotten really ugly.

    The variables should be private because the interface should _usually_
    be one of the class providing a higher-level abstraction, so clients do
    NOT just get and set values. One basic principle is generally as "don't
    ask -- tell". The idea is that code outside the class should NOT request
    information about the class state before making a modification. e.g.
    this would be bad:

    some_class x;

    if (x.getsomevalue() < 10)
    x.setsomeothervalue(12);

    Instead, the class itself should contain that intelligence, and the
    outside code should just do something like: x.dowhatever(12);

    Occassionally, however, you run into something that really makes sense
    with an interface with what at least look and act like public variables.
    In this case, (at least IMO) get/set methods are the wrong way to go. If
    you really want unrestricted access to these variables, then just make
    the public. If your get/set methods really do something (typically
    range-checking) to assure the values are valid, then you should create
    something that looks and acts like a public variable, but gives you the
    control you need (e.g. carries out the aforementioned range-checking).

    Since range-checking is so common, I've written a small template that
    implements it:

    #include <exception>
    #include <iostream>
    #include <functional>

    template <class T, class less=std::less<T> >
    class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
    return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
    if (check(value))
    throw std::domain_error("Out of Range");
    val_ = value;
    }

    public:
    bounded(T const &lower, T const &upper)
    : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) { assign(init); }

    bounded &operator=(T const &v) { assign(v); return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
    T temp;
    is >> temp;

    if (b.check(temp))
    is.setstate(std::ios::failbit);
    else
    b.val_ = temp;
    return is;
    }
    };

    This would be used like:

    struct X {
    bounded<int> x;
    bounded<int> y;

    X() : x(1, 100), y(0, 200) {}
    };

    and now code that uses these can simply treat x and y as public
    variables (since they are) but you still have full control to assure
    that only valid values are assigned to them. It's also possible to pass
    the bounds as template parameters, so those would look like:

    bounded<int, 1, 100> x;
    bounded<int, 0, 200> y;

    But this doesn't work for floating point ranges (OTOH, it has some
    advantages, such as making different ranges different types, so
    accidentally assigning from one to another is an error -- though an
    explicit cast makes it possible when needed).

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Feb 16, 2007
    #8
  9. Vincent RICHOMME

    abadura Guest

    Try out this code:

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    #include <iostream>
    #include <string>

    using namespace std;



    template<typename class_T, typename T, typename const_reference_T =
    const T&> class property {
    public:
    typedef T value_type;
    typedef const_reference_T const_reference_type;
    typedef class_T class_type;

    typedef const_reference_type (class_type::*get_type)() const;
    typedef void (class_type::*set_type)(const_reference_type);
    typedef value_type& (class_type::*get_ref_type)();

    public:
    property(class_type* p_obj, get_type p_get_fun, set_type p_set_fun,
    get_ref_type p_get_ref_fun) : m_p_obj(p_obj), m_p_get_fun(p_get_fun),
    m_p_set_fun(p_set_fun), m_p_get_ref_fun(p_get_ref_fun) {}

    T& operator =(const_reference_type value) {
    (m_p_obj->*m_p_set_fun)(value);
    return (m_p_obj->*m_p_get_ref_fun)();
    }

    operator const_reference_type() {
    return (m_p_obj->*m_p_get_fun)();
    }

    private:
    class_type* m_p_obj;

    get_type m_p_get_fun;
    set_type m_p_set_fun;
    get_ref_type m_p_get_ref_fun;

    };



    class example {
    public:
    example() : width(this, &example::get_width, &example::set_width,
    &example::get_ref_width), title(this, &example::get_title,
    &example::set_title, &example::get_ref_title), m_width(0), m_title()
    {};

    property<example, int, int> width;
    property<example, string> title;

    private:
    int m_width;

    int get_width() const {
    return m_width;
    }

    void set_width(int width) {
    m_width = width;
    }

    int& get_ref_width() {
    return m_width;
    }


    string m_title;

    const string& get_title() const {
    return m_title;
    }

    void set_title(const string& title) {
    m_title = title;
    }

    string& get_ref_title() {
    return m_title;
    }

    };



    void test(int val) {
    cout << "test(int): " << val << endl;
    }

    void test(const string& val) {
    cout << "test(string): " << val << endl;
    }

    int main(int, char* []) {
    example ex;
    cout << "ex.width: " << static_cast<int>(ex.width) << endl;
    cout << "ex.title: " << static_cast<const string&>(ex.title) << endl;
    ex.width = 1;
    ex.title = "title";
    cout << "ex.width: " << static_cast<int>(ex.width) << endl;
    cout << "ex.title: " << static_cast<const string&>(ex.title) << endl;
    test(ex.width);
    test(ex.title);
    return 0;
    }
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    The code compiles and workes fine on GCC (however I do not remebrer
    which version) and MS VS 2005.
    Note that I pass pointer "this" in constructor - which is not a
    good idea to do. However this code does not use this value before the
    construction completes so no problem - bu if you want to remove this
    you can always allow late initialization of this pointer (but then you
    would HAVE to remember to do this).

    The idea behind this is to make a tamplate class which will allow
    property-like behavior. You must pass some arguments as you can read
    from the code. const_reference_T is used to allow the behavior with
    basic types where you do not use reference but a simple type.

    As you can see using to << operator requires explicit cast. You can
    remove this by decalring the operator for property class.

    Naturally the class can be easly modified to react on other needs
    or to simulate get-only or set-only properties. I think that using
    template metaprograming could improve the code. This was just a quick
    try to give you some ideas.

    Adam Badura
     
    abadura, Feb 16, 2007
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Amir
    Replies:
    3
    Views:
    614
  2. nc
    Replies:
    1
    Views:
    519
    nice.guy.nige
    Feb 3, 2005
  3. Replies:
    2
    Views:
    353
  4. Andrey Koptyaev
    Replies:
    0
    Views:
    358
    Andrey Koptyaev
    Oct 1, 2006
  5. Jeannie
    Replies:
    15
    Views:
    911
    Jeannie
    Aug 30, 2005
Loading...

Share This Page