Thread: returning reference

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    630

    returning reference

    Hello

    If I have the following data structure:

    Code:
    class options {
    public:
    	void set_value(int v) { m_value = v; }
    	int get_value() { return m_value; }
    private:
    	int m_value;
    };
    
    class someclass {
    public:
    	options &get_options() { return m_options; }
    private:
    	options m_options;
    };
    What is the right way to return m_options by reference?
    Isnt this right:
    Code:
    options &get_options() const { return m_options; }
    so that I'm allowed to call get_options().set and get functions?

    Where should I put the 'const' in this case?

    Thanks for help!

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Code:
    options &get_options() const { return m_options; }
    This is correct - you are not modifying the content of your class.


    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    630
    Why do I get an error with this:
    Code:
    error C2440: 'return' : cannot convert from 'const options' to 'options &'

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Ah, yes, I suppose if you do return a reference to a member variable, you are allowing the code outside the object to modify the object itself, so although the member function itself isn't doing any changing, it will potentially be modified by the new user of the reference: so either no const at all, or const option &get...() const ... [you can have both].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    You have a choice between a getter/setter pair:
    Code:
    const options& get_options() const { return m_options; }
    void set_options(const options& new_options) { m_options = new_options; }
    Or to provide:
    Code:
    const options& get_options() const { return m_options; }
    options& get_options() { return m_options; }
    For the latter choice the non-const version of get_options() will be used unless the object is const.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    May 2006
    Posts
    630
    Quote Originally Posted by laserlight View Post
    You have a choice between a getter/setter pair:
    Code:
    const options& get_options() const { return m_options; }
    void set_options(const options& new_options) { m_options = new_options; }
    Or to provide:
    Code:
    const options& get_options() const { return m_options; }
    options& get_options() { return m_options; }
    For the latter choice the non-const version of get_options() will be used unless the object is const.
    Which options is better? What do you guys prefer?

    The first option seems better to me, but I guess in that case I have to overload = operator for options class? Will it compile after I do this?

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by l2u View Post
    The first option seems better to me, but I guess in that case I have to overload = operator for options class? Will it compile after I do this?
    You'd have to do that anyway even in the second example, because presumably the caller is obtaining a non-const reference in order to assign to it, right?

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The first option seems better to me, but I guess in that case I have to overload = operator for options class?
    I prefer the first option too, and you do not need to write operator= since the compiler provided version will work correctly. Of course, if the compiler provided version would not work correctly, then you should implement it yourself either way.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I tend to prefer using set/get these days with a little helper class:

    Code:
    	template<typename Type, typename Class> class CUtilityMember
    	{
    	private:
    		Type Data;
    		typedef const Type& (Class::*GetFncPointer)();
    		typedef void (Class::*SetFncPointer)(const Type& NewData);
    		GetFncPointer m_pGet;
    		SetFncPointer m_pSet;
    		Class* m_pClass;
    	
    	public:
    		CUtilityMember(Class* pClass, GetFncPointer pGet = NULL, SetFncPointer pSet = NULL);
    		CUtilityMember(const Type& NewData, Class* pClass, GetFncPointer pGet = NULL,
    			SetFncPointer pSet = NULL);
    		CUtilityMember& operator = (const Type& NewData);
    		operator Type () const;
    	};
    
    	template<typename Type, typename Class> CUtilityMember<Type, Class>::CUtilityMember
    		(Class* pClass, GetFncPointer pGet, SetFncPointer pSet): m_pClass(pClass), m_pGet(pGet),
    		m_pSet(pSet) { }
    	template<typename Type, typename Class> CUtilityMember<Type, Class>::CUtilityMember
    		(const Type& NewData, Class* pClass, GetFncPointer pGet, SetFncPointer pSet):
    		Data(NewData), m_pClass(pClass), m_pGet(pGet), m_pSet(pSet) { }
    	template<typename Type, typename Class> CUtilityMember<Type, Class>&
    		CUtilityMember<Type, Class>::operator = (const Type& NewData)
    	{
    		if (m_pSet)
    			(m_pClass->*m_pSet)(NewData);
    		else
    			Data = NewData;
    		return *this;
    	}
    	template<typename Type, typename Class> CUtilityMember<Type, Class>::operator Type () const
    	{
    		if (m_pGet)
    			return (m_pClass->*m_pGet)();
    		else
    			return Data;
    	}
    And to use it:

    Code:
    		CFilter(CString strExt = _T(""), CString strDescription = _T("")): strExt(strExt, this),
    			strDescription(strDescription, this) { }
    		CUtilityMember<CString, CFilter> strExt;
    		CUtilityMember<CString, CFilter> strDescription;
    Optionally, if you want to extra things rather than just set/get the value of the class, then you can provide a class function pointer to a get/set function within your own class.
    It's not 100&#37; finished yet, but it will allow you to do

    Myclass.MyVar = somevalue;
    And
    sometype somevalue = Myclass.MyVar;

    Without sacrificing the encapsulation. You can add more operators as necessary.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    May 2006
    Posts
    630
    Quote Originally Posted by laserlight View Post
    I prefer the first option too, and you do not need to write operator= since the compiler provided version will work correctly. Of course, if the compiler provided version would not work correctly, then you should implement it yourself either way.
    I still get the error if I define the set function as you said. What am I doing wrong?

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I still get the error if I define the set function as you said. What am I doing wrong?
    Post the smallest and simplest program that demonstrates the error, and also post the exact error message.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    May 2006
    Posts
    630
    Quote Originally Posted by laserlight View Post
    Post the smallest and simplest program that demonstrates the error, and also post the exact error message.
    Sorry, my bad - I forgot to put const in front of get_options() function.

  13. #13
    Registered User
    Join Date
    May 2006
    Posts
    630
    I want to make sure about something..

    If I have this design:

    Code:
    class options {
    public:
    	void set_value(int v) { m_value = v; }
    	int get_value() { return m_value; }
    private:
    	int m_value;
    };
    
    class subclass {
    public:
    	subclass(options &opt) : m_options(opt) { }
    private:
    	options &m_options;
    };
    
    class someclass {
    public:
    	someclass() : m_subclass(m_options) { }
    
    	const options &get_options() const { return m_options; }
    	void set_options(const options& new_options) { m_options = new_options; }
    private:
    	options m_options;
    	subclass m_subclass;
    };
    Now I do:
    Code:
    someclass test;
    test.set_options(some_new_options);
    Can this make a problem since I pass a reference of m_options to subclass object?
    I think this shouldnt be a problem since it will only reassign the values or am I wrong?

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It won't cause a problem because you're assigning to a non-reference type.
    But I still question if this approach is a good one. You're going to have to remake that class for every other class that might use it. And I still feel using = to assign and just the name to get is a better approach (I may be wrong on that).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Registered User
    Join Date
    May 2006
    Posts
    630
    Why will this give the following error:

    Code:
    class someclass {
    public:
    	const someobject &get_object(std::string str) const { return m_map[str]; }
    	void set_object(std::string str, object obj) { m_map[str] = obj; } 
    	
    private:
    	std::map<std::string, someobject> m_map;
    };
    error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const someclass::map' (or there is no acceptable conversion)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM