1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
using namespace std;
enum ConnectionStatus
{
Disconnected = 0,
Connected
};
class Status
{
public:
inline ConnectionStatus getConnectionStatus()
{
return connectionStatus;
}
inline void setConnectionStatus(ConnectionStatus val)
{
connectionStatus = val;
}
private:
ConnectionStatus connectionStatus = ConnectionStatus::Disconnected;
};
class Foo
{
public:
inline Status getStatus()
{
return status;
}
inline void setStatus(Status val)
{
status = val;
}
private:
Status status;
};
int main()
{
Foo f;
cout << "Init Connection Status: " << f.getStatus().getConnectionStatus() << endl;
f.getStatus().setConnectionStatus(ConnectionStatus::Connected);
cout << "After setting status: " << f.getStatus().getConnectionStatus() << endl;
return 0;
}Init Connection Status: 0 After setting status: 0
getStatus(), in the call f.getStatus().setConnectionStatus(Connected), returns-by-value a copy of f.status and .setConnectedStatus(Connected) sets the .connectionStatus of the copy, rather than of f.status?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
using namespace std;
enum ConnectionStatus
{
Disconnected = 0,
Connected
};
class Status
{
public:
inline ConnectionStatus getConnectionStatus() // [1]
{
return connectionStatus;
}
inline void setConnectionStatus(ConnectionStatus val)
{
connectionStatus = val;
}
private:
ConnectionStatus connectionStatus = ConnectionStatus::Disconnected;
};
class Foo
{
public:
inline Status& getStatus() // Return a REFERENCE to this->status
{
return status;
}
inline void setStatus(Status val)
{
status = val;
}
private:
Status status;
};
int main()
{
Foo f;
cout << "Init Connection Status: " << f.getStatus().getConnectionStatus() << endl;
f.getStatus().setConnectionStatus(ConnectionStatus::Connected);
cout << "After setting status: " << f.getStatus().getConnectionStatus() << endl;
return 0;
}const reference, because leaking a non-const references to "internal" data is usually undesired. It would allow the caller to modify "internal" data (via the reference) without using the "setter" function!const reference from a "getter" function can make sense, e.g. if the data to be return is big and you don't want to return a copy. But, in this case, you are just returning a simple enum value (eseentially an int), so returning a reference doesn't make much sense.const reference from your "getter" function – typically a reference to some sort of "nested" object that you explicitly do want the caller to be able to modify – a separate "setter" function is not needed and wouldn't make much sense!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
enum ConnectionStatus
{
Disconnected,
Connected
};
class Status
{
public:
inline ConnectionStatus getConnectionStatus() const // <-- return current status "by value"
{
return connectionStatus;
}
inline void setConnectionStatus(const ConnectionStatus val)
{
if ((val != Connected) && (val != Disconnected)) {
std::abort(); // <-- input validation: protect us from "rogue" value
}
connectionStatus = val;
}
private:
ConnectionStatus connectionStatus = ConnectionStatus::Disconnected;
};
class Foo
{
public:
inline Status &getStatus() // <-- return mutable (non-const) reference to "inner" Status object
{
return status;
}
private:
Status status;
};
int main()
{
Foo foo;
std::cout << "Init Connection Status: " << foo.getStatus().getConnectionStatus() << std::endl;
foo.getStatus().setConnectionStatus(ConnectionStatus::Connected);
std::cout << "After setting status: " << foo.getStatus().getConnectionStatus() << std::endl;
// foo.getStatus().setConnectionStatus((ConnectionStatus)42);
return 0;
}Init Connection Status: 0 After setting status: 1
inline directive)
| coder777 wrote: |
|---|
| I suggest to remove the getter/setter overhead and make the member public. |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct ConnectedThing
{
enum class ConnectionStatus
{
Disconnected,
Connected
};
virtual ConnectionStatus status() const;
virtual ConnectedThing & connect( const std::string & );
virtual void disconnect();
};
struct HTTPServer : public ConnectedThing
{
ConnectionStatus status() const
{
return _server_fd < 0
? ConnectionStatus::Disconnected
: ConnectionStatus::Connected;
}
...etc...
private:
int _server_fd;
};1
2
3
4
Status Foo::getStatus()
{
return status;
}f.getStatus().setConnectionStatus(ConnectionStatus::Connected);1
2
3
auto s = f.getStatus();
s.setConnectionStatus(ConnectionStatus::Connected);
f.setStatus(s);1
2
3
4
5
6
7
8
class Foo
{
public:
void setConnectionStatus(ConnectionStatus val)
{
status.setConnectionStatus(val);
}
...class Status?| coder777 wrote: |
|---|
| Don't make your life harder than necessary. When you have both setter and getter your member variable is basically public just with overhead. So I suggest to remove the getter/setter overhead and make the member public. |
| jonnin wrote: |
|---|
| I realize this code may be just an example to demonstrate for a question and study purposes. But if you are crafting a program with this kind of monstrosity in it, I beg you to reconsider. |
| kigar64551 wrote: |
|---|
| In most cases, a "getter" function should not return a non-const reference, because leaking a non-const references to "internal" data is usually undesired. It would allow the caller to modify "internal" data (via the reference) without using the "setter" function! Returning a const reference from a "getter" function can make sense, e.g. if the data to be return is big and you don't want to return a copy. But, in this case, you are just returning a simple enum value (eseentially an int), so returning a reference doesn't make much sense. In cases where you do return a non-const reference from your "getter" function – typically a reference to some sort of "nested" object that you explicitly do want the caller to be able to modify – a separate "setter" function is not needed and wouldn't make much sense! |
const) reference or pointer to the "internal" (private) data via your "getter" functions (or in any other way), because the caller could use the mutable reference to modify the "internal" data without using your "setter" function – which contradicts the reason to have a "setter" function.const) reference to the "inner" object. But then no corresponding "setter" function is needed, in the "outer" object, because callers can modify the "inner" object already! In the above example, this is the case with Foo::getStatus(), which returns a reference to the inner ConnectionStatus instance.1
2
3
Foo foo;
foo.getStatus().setConnectionStatus(ConnectionStatus::Connected); // #1
foo.setConnectionStatus(ConnectionStatus::Connected); // #2 operator()() to return the value (the getter ) and operator()(/*some arguments*/) to set the value. But I would only do that if there was some reason not to use the interface, such as with strong types.mutex?