Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Scott Meyers's advice to prefer non-member non-friend methods apply to object construction?

Let's say I have a class:

class C{
  int x_;
  int y_;
public:
  C(int x, int y): x_(x), y_(y){}
};

Then I want to add construction from a string, which would just parse x and y. Before reading Meyers's book I would usually make it another constructor in class C. However, it's also possible to make it non-member non-friend:

C CFromString(const std::string& s){
  int x, y;
  //...parse them somehow, throw exception if needed...
  return C(x,y);
}

To me this is standard situation for many "value classes", when there is a "main" constructor which sets private members to provided values (probably checking there correctness). Other constructors for such classes are often just calculate these values from some other arguments.

Are there any drawbacks in making such constructors non-member non-friends like in my example?

Upd. I understand the Meyers's advice, and what are the advantages of NMNF functions. There is just no examples of NMNF object construction in his book, so I want to ensure that his advice applies to construction as well.

like image 801
Dmitry J Avatar asked Mar 29 '17 22:03

Dmitry J


2 Answers

If you start adding constructors for every possible way a class can be serialized, you are tightly coupling that class with those serialization methods.

It is preferred that you separate the class and the serializer in order to separate concerns. Let the class focus on what the class does and the serializer on what it does (read json or whatever)

You have to consider that your class might be serialized from a file, from a socket, from json, from xml, from a database...from any number of things.

That's why in modern programming we use interfaces. We also make use of the Factory pattern.

like image 180
Christopher Pisz Avatar answered Nov 06 '22 16:11

Christopher Pisz


One drawback is a bit of inconsistency, which is an esthetic concern.

You're calling a CFromString constructor function rather than invoking a constructor called C. The relationship between them is arbitrary, just through the C prefix in the name.

If you make it a static member function, then you can call it C::FromString so that it belongs to the class.

If this is done all over the place in a large project, some sort of convention would help. Like say, whenever we have a class C, and a non-member constructor function for making C-s, let's always call it CCons, and then always use overloading for different types. Thus, if we have a Widget class, we then call our overloaded family WidgetCons:

Widget WidgetCons(const std::string &s) { /* make it from string */ }
Widget WidgetCons(int i) { /* make it from int */ }

and so on. If this is consistent in our 250,000 line codebase, whenever someone sees any FooCons or BarCons, they know exactly what it is.

like image 3
Kaz Avatar answered Nov 06 '22 17:11

Kaz