I have a class that has the following variables/members:
First Name
Last Name
Age
Address
etc..
I want to create getter-methods for each of them that returns the values. This could become quite large depending on the class.
Is there a quicker or more object-oriented way that would allow me to do this just using one method? The only way I can think about is to have a method that takes a parameter of the name of the variable to be returned; however, the types for the method would change depending on if it was returning a string, int etc..
Does anyone have a solution?
Why do you need those values outside the class? If you have code that is not in Person that calls 4 or 5 Person GetWhatever() methods and glues the strings together, stuffs commas between them and so on, move that code into Person. Do that enough and no code outside Person needs to call your getters.
Some classes are logic-free, they just hold values, and they expect outside objects to do all the work. In C++, using a struct for that makes your intention clear. If you insist that code outside Person needs to arbitrarily access elements of Person, it's probably a struct, not a class. If you insist it's a class, prove it by adding some actual business logic to it.
No, there is no "better" way which is still object-oriented. You should define one public "getter" method for each private member variable which needs to be access outside the class. You should also define a setter method, if the variable is meant to be set from outside the class.
If you want easy to define setter/getter - make it on single member level. Make member template with setter/getter and define is as public element of your class:
template <class Type>
class Member {
public:
Member(const T& value = T()) : value(value) {}
void setValue(const Type& t) { value = t; }
T getValue() const { return value; }
private:
T value;
};
Use it in your class:
class Person {
public:
Member<std::string> firstName;
Member<std::string> lastName;
Member<std::string> address;
Member<unsigned> age;
};
And usage:
int main() {
Person one;
one.firstName.setValue("Joe");
one.age.setValue(33);
}
If your need some constraints (like range checking) then define some RangeCheckingMember template. If you need the members to be dependent on each others - then make relationship between them by pointers/references.
Consider making that parameter lookup using a template member function that takes a default value in a given type.
template<typename ValueType>
const ValueType& get(const KeyType& key, const ValueType& default value) {
...
};
You still have to enumerate (or otherwise list) a KeyType of all your values (or use std::string which might be fine in larger cases) and work back and forth with your storage on the ValueType.
So, this doesn't really help you much until you decide you need arbitrarily large or completely dynamic values. At this point, you need to implement a map which can hold any type which requires either hideous unions or a template wrapper derived class from a common base class used in the map.
The upside to this is that a getKeys() method can present all of the keys available in the class -- something quite useful for dynamic GUIs and message handling.
If you are using a library in which everything subclasses some Object class (QObject for example), you can use a map of (string, object) to hold all your data and then access it with:
Object get(string name) { return memebers[name]; }
members is std::map<std::string, Object>
You will need to use type casts of course.
Button* my_var = static_cast<Button*>(my_class.get("my_button"));
// get returns Object
You can also use Qt's property system if you use Qt. This is not standard c++, but qmake and moc work on many operating systems.
all right.since you know what you want.
void get(int flag, void *return_value)
get the return_value typd casting to what you want.
thanks
Related
In my company, we generate code from XML. The code generator generates header files that contain Messages, and each message contains only data. NOTE we don't do any validation while setting or returning data; also, we don't have to take care of the state, i.e., data x and data in a message are independent; if x is changed, we don't need to change the state of y.
Current header file
class somemessage
{
private:
Field _field;
.......
public:
Field& getfield(){...}
const Field& getfield() const {...}
void setfield(const Field& field){....}
} ;
Do we still need data hiding here if it's only data? Do we require getter and setters in these headers, or can se make it simple as following.
struct somemessage
{
Field field;
};
We can make the message read-only when required using const as following.
void message_consumer(const somemessage& message)
{
message.field = somevalue; // compilation error
}
What are the disadvantages of this approach, and what are the advantages of using accessors and mutators?
If you have the following pattern:
class A {
public:
void SetFoo(const Foo& newFoo) {
f = newFoo;
}
const Foo& GetFoo() const {
return f;
}
protected:
private:
Foo f;
};
That is, you have a getter/setter pair and all they do is have a single return statement and a single assignment expression, then there's no need for the data member to be private and instead just make the data member public and remove the getter/setter pair.
class A {
public:
Foo f;
protected:
private:
};
If your getters/setters do anything else, or are in any way more complicated, then yes, having a getter/setter pair is fine.
In terms of using a struct versus a class, I go with struct if the type is strictly only data; no functions, no constructors. If for whatever reason the data type needs functions, then it should be declared as a class.
Writing a getter like this:
Field& getfield(){...}
is not encapsulation. A user can do this:
Field& decapsulated = x.getField();
and now they have a reference to the private member that they can use to do what they like. All checking and bookkeeping in the setter is futile, because the user does not need it to modify the private member:
decapsulated = some_other_field;
Proper encapsulation has advantages. Though plain old structs with only public members have their place as well. If however all you do is writing boilerplate that does not encapsulate the data, you can leave away the boilerplate. Eventually it is up to you to decide what to use. Encapsulation has lots of advantages, but it is not a must.
Getters returning non-const references can be useful as convenience methods. They can provide easy means for the user to access the class data. Compare for example to std::vector::operator[] or std::vector::at(). Though one should not confuse that with data encapsulation.
This is what I am working with (roughly)
template<class t>
class Manager{
//this class has a internal map which you can use to store classes of 1 type with a key.
//This class is also a templated singelton (which means that you can call getInstance() for
//any type like so: Manager<someType>::getInstance()
//...
public:
void addComponent(int key, const t& newThing){
//add to internal map
}
void addComponent(int key, AddsFriends<t>& newThing){
//add newThing & Friends to map
}
}
template<class t>
class AddsFriends<t>{
public:
virtual void addFriends(int key){
//add the Friend classes to the maps upon being called
}
}
This is a exercise I came up with so its not really anything too logical. Basically when I get a Manager from any type I should be able to add a entry to it with a specified key and component (which it will copy upon insertion.) I can also retrieve the inserted classes using a get function (not shown above).
When a type is used that extends "AddsFriends" I want to be able to call "addFriends" with a key so any "Friend-instances" can be added to many types. This way I kinda want to make something where I can have a class called "Person" and have it add a "Hat" class to the corresponding manager with the same id when the person gets added (therefore every "person" inserted also causes a "hat" to be inserted). I hope this is understandable.
However, Im having trouble determining if this interface is implemented or not. I tried to do dynamic_cast and just check for an exception, but that would require loosing the const-expression -> makes insert statements longer (since I have to store the variable "just" for it to act as an initialiser instead of just calling the constructor in the add-function)
How could I get c++ to pick the correct function here?
EDIT:
Here is how I intend to use manager:
int key;
Manager<std::string>& stringManager = Manager<std::string>::getInstance();
stringManager.addComponent(key, "Hello there");
Manager<Foo>& fooManager = Manager<Foo>::getInstance();
fooManager.addComponent(key, Foo("Some init Params"));
class Foo: public AddsFriends<Foo>{
private:
std::string *friendString = nullptr;
//Other stuff
public:
//Do constructor and whatever else you want
virtual void addFriends(int key){
//add the Friend classes to the maps upon being called
Manager<std::string>& stringManager = Manager<std::string>::getInstance();
stringManager.addComponent(key, "This belongs to the foo component!");
//Note: The way I do this changed in my actual implementation, where I return a reference directly in the addComponent method. When I asked this question I was still using this function just because I didnt want to make the problem more complicated before I could get the old version to work. getNewest just return the reference to the newest component.
this->friendString = &stringManager.getNewest();
}
}
The reason why I want friends to be added in this way is so that I can have "components" that use the same functionality as other components through composition, but still make the "components" they use accessible through the proper manager. So lets say I have a component called "Cube" and a component called "Position". The cube holds the data that you need to represent a cube, but it also has a position assigned to it. If I just did regular composition with a "Position" attribute, it would work, but the Position wouldnt be in the PositionManager, like it should. This would result in a incomplete set of managed components and kinda ruins the point of having these managers in the first place :/.
The simplest option, I think, will be to specialize Manager.
template <class t>
class Manager {
public:
void addComponent(int key, const t& newThing){
//add to internal map
}
};
template <class t>
class Manager<AddsFriends<t>> {
public:
void addComponent(int key, AddsFriends<t> const& newThing){
//add newThing & Friends to map
}
};
Classic way to get a reference to class member or its value we use getters like getValue(). Could this be an alternative way? :
class A{
ComplexClass value_;
public:
//No need. ComplexClass const& getValue() const { return value_; }
ComplexClass const& value = value_; /// ???
}
Will this work? How do you like such syntax?
UPD.
This point is to make user code simpler. Personally I better like auto x = a.value than auto x = a.getValue(). Of course this is a deal of taste.
Will this still work nice if:
class A{
public:
ComplexClass const& value = value_;
protected:
ComplexClass value_;
}
I ask because I met some troubles with one compiler.
One of the main reasons to prefer member functions over data members is flexibility and maintainability. If you only ever wrote some code once, perfectly, and it would never be changed or reused, then you could certainly have public data members that users refer to directly.
The interesting question is what happens when your code doesn't meet these criteria, e.g. if it is going to evolve, and if other people start using it. Then once you have a public data member, you are forced to always have that data member. Details of your class layout are now part of your public contract. Simple refactorings like moving common parts into nested member objects are no longer private and break existing users.
Your proposed reference data member adds almost no benefit over a public data member (except for in very trivial cases), and unlike member functions, non-static data members affect the class layout. Class layout is another thing you will probably want to keep stable once you have users, so that old, compiled libraries can continue to be linked against new user code. Member functions are much easier to evolve while keeping the data layout unchanged.
There's a nice example in the standard library where such a mistake was made: std::pair<T1, T2> is specified to contain public data members first and second. That means that all user specializations must adhere to the same specification, and cannot easily employ things like base layout optimizations. Had first and second been specified as member functions, such optimizations could be applied trivially.
How can I do this way easier:
struct Parameters {
public:
int Parameter1;
std::string Parameter1;
int Parameter2;
std::string Parameter2;
}
Isn't there "var" in C++ like in .NET ? I need parameters to be able to be integers and strings.
You have the key word 'auto' in C++ but it's on C++0x and C++1x, it's the compiler which will decide the type and it can't change after the compilation.
You're probably looking for something like boost::variant: http://www.boost.org/doc/libs/1_56_0/doc/html/variant.html
You can use Union, but you will still need to know at compile time what type you are assigning. You can sort of hide this by using templates with implicit typing to assign values, but you will still have to know the appropriate type when reading the value. Not sure how useful that would be though.
You could also use polymorphism and your own (template) wrapper class in place of the built in types.
I suggest you factor out the common code and set up to use a factory.
Use of a Factory
The problem is that you don't know the type of the parameter until you parse the string. The best method is to keep everything as a string or create a Factory and use a base class. For more research, see "c++ factory design pattern example".
struct Base_Parameter
{
std::string& parameter_as_string;
virtual void extract_parameter(const std::string& parameter_string) = 0;
};
struct Int_Parameter : public Base_Parameter
{
int parameter_value;
void extract_parameter(const std::string& parameter_string)
{
std::istringstream param_stream(parameter_string);
param_stream >> parameter_value;
}
}
Your parameter "list" would be either a container of pointers to the base class (if the types are unknown) or you could have a container of the descendent struct:
struct Parameter_Container
{
std::vector<Int_Parameter> parameters;
};
As for the factory, the factory would be an object that could create parameter objects based on some criteria. It would return a pointer to the base class.
Note: Unless you are on a tightly constrained platform, such as an embedded system, don't worry about overlapping memory locations to save room.
what is the best way to share different objects between some classes in a generic manner?
For example class A can store an object o with a string as a key in a register and class B can access it using the key.
My first idea was to create a register (singleton) which has a hashtable as a member using a string as the key and a void pointer as the value. But there must be a better solution for this?
From your clarification:
template <typename OB>
class A {
std::unordered_map<std::string, OB> hash;
public:
OB const& get(std::string const&) const;
void add(OB const& object, std::string const&);
};
That is to say, A<int> is a class that stores int objects by name, and A<std::set<float>> is a class that stores sets of floats by name. You can't mix them. That's in line with the basic C++ philosophy: the type of theA.get("foo") is determined at compile time, not by what you put in at runtime.
In C++, you can however "mix" multiple derived types, if you'd need this for your particular case. That's a bit more complicated:
template <typename Base>
class A {
std::unordered_map<std::string, std::unique_ptr<Base>> hash;
public:
Base const& get(std::string const&) const;
template<typename Derived> void add(std::string const& name, Derived const& object)
{
std::unique_ptr<Base> copy(new Derived(object));
hash.emplace(std::make_pair(name, std::move(copy)));
}
};
There's some slight trickery here as hash should be the only owner of the copy, but it's constructed outside and therefore needs to be moved it. (For extra-fancy, I could add a Derived&& overload that eliminates that copy too)
I would suggest that all the classes that you must register have a common supertype.
For instance, if you have to store instances of classes One, Two, and Three you could define a (possibly empty) class Object from which your class can derive:
class Object {}
class One : public Object { /* One's member and methods */ }
class Two : public Object { /* Two's member and methods */ }
class Three : public Object { /* Three's member and methods */ }
If you follow MSalters question you can then declare a A<Object*>.
If you cannot have one supertype (for instance because you cannot change One, Two or Three) you may look at Boost.Variant. Again, you can declare a A<boost::variant<One, Two, Three> >.
The first question is: how does B know the type of the stored object,
and what it can do with it? Perhaps the simplest solution is just to
have one registry per type. Alternatively, something like
boost::variant can be used, or you can ensure that all types derive
from a common base, and store a pointer to that. Unless you actually
need to support polymorphism (e.g. operating on an object without
knowing its exact type), I'd avoid the pointer solution, however.
The best way is to use a shared_ptr, instead of a naked pointer. If you have a C++11 compliant compiler, shared_ptr is in the std namespace. Otherwise, use the Boost implementation.