0

If a class is written well, you should be able to gleam all relevant information about the class simply by looking at its header.

If one sees that the constructor is marked explicit:

  1. What should one assume to be absolutely true about this class?
  2. What should one assume to be potentially true about this class.
  3. What sort of bugs could one expect, if explicit is violated somehow?

If what I am asking is not clear; In the same way that if I see a member function marked virtual void sneed() = 0;

  1. Its absolutely true that this is an abstract class
  2. Its potentially true that this is some sort of factory
  3. And that if I do not impliment it, the program will not compile.

Thanks.

9
  • 1
    IMO, this is not a particularly useful way to think about these things. These keywords tell you some things, but a big part of "all relevant information" comes from the meaning of the class and the methods - i.e., it might come from documentation comments present in the header. E.g. for your virtual example, it is in general not at all likely that it is some sort of a factory. This might be true in the context of particular codebase, but in general, it doesn't have to be a factory in any way. For explicit, you can infer that the devs wanted to prevent implicit conversions in client code. Jul 8, 2022 at 22:39
  • 1
    So, the idea is that, when you put explicit, you prevent the compiler from making implicit conversions using that constructor. E.g., when a function takes a float, and you type in an int like 42, it is implicitly converted to a float, but if a function takes an int, and you attempt to pass a float like 3.14, you get a warning in C++ and an error in C#, because (a) a loss of data occurs, and you may care about that, and (b) even if you intended to do this, maybe the default rounding/truncation scheme doesn't do what you thought it does. So there's potential for subtle errors. 1/3 Jul 9, 2022 at 1:18
  • 1
    If someone placed explicit on their constructor, it indicates that they thought that implicit conversions (from the type of the constructor argument to the type of the class) would potentially cause more trouble then the convenience of implicit conversion was worth. Exactly why they thought this depends on what the actual class is supposed to represent and how it's meant to be used, and to some extent on their personal preferences. 2/3 Jul 9, 2022 at 1:18
  • 1
    As for QObject, the constructor takes in a QObject*, a pointer to a parent - which means that the compiler can use it to implicitly "convert" a pointer into a QObject. So, if you accidentally passed some pointer you had to a function that takes a QObject by value, the compiler would implicitly call that constructor to create a new QObject that has the pointer you passed in as a parent - which is probably not what you wanted; explicit prevents that. (BTW, you didn't mention QObject anywhere before your last comment, so I was talking in general terms) 3/3 Jul 9, 2022 at 1:19
  • 1
    Not pointer of any type; if you already have a QObject-pointer (QObject*) to some qt object already in memory, and it needs to be assigned (maybe by accident) to a variable or a parameter of type QObject, the compiler has to figure out if that's valid. So it will go "Oh, look, there's a constructor that takes a single QObject* and spits out a QObject! Seems like it lets me convert between these two!". The problem is, the compiler is wrong about what this constructor does - it's not meant for conversions. Here's a demo, click the "Fork" btn to edit. Jul 9, 2022 at 2:59

1 Answer 1

2

Some constructor are conversion constructors, i.e. it can be used to transform an object of a type provided as argument, into an object of that class. This can sometimes lead to nasty bugs, when the compiler tries to use such a conversion behind the scene in an unexpected way (example).

If the conversion constructor is marked explicit, the compiler will not use it for conversions without an explicit request, i.e.

only where the direct-initialization syntax or where casts are explicitly used

Note that the explicit keyword may also be used with conversion functions, to prevent the same kind of problems.

In conclusion, you cannot infer anything general about the class. explicit has no impact on the class but only restricts the way its constructor (or conversion functions) may be used.

10
  • Is any constructor not marked explicit technically a conversion constructor?
    – Anon
    Jul 9, 2022 at 8:35
  • 2
    Indeed, according to the standard: "A constructor that is not explicit specifies a conversion from the types of its parameters (if any) to the type of its class. Such a constructor is called a converting constructor." - This definition is very broad, and somewhat counter-intuitive. In practice, conversion constructors, i.e. with the true intent to convert (and perhaps a corresponding conversion function to convert back), are mostly with one argument of a different type. And here are most of the problems that explicit addresses.
    – Christophe
    Jul 9, 2022 at 9:05
  • 2
    @Anon The conclusion of this example is that explicit can (and often does) solve ambiguities that are not intrinsically related to the class. And therefore my claim that you cannot deduce anything about the class itself. Your approach of drawing general hypotheses based on class definition is interesting. But to obtain valid results, the hypotheses need to be formulated in general and verified on specific cases/examples. The danger is to get biased by the example, and want to find a general rule that in reality applies only to some specific cases.
    – Christophe
    Jul 9, 2022 at 9:53
  • 1
    I went through your class, ran the error, and I get everything you have said. Point made beautifully. But Im asking something more... annoyingly esoteric. Although I have thought a lot on it. I think there really is almost nothing general you could assume about a constructor marked explicit. If you think of something, let me know. Otherwise I'll leave it at this.
    – Anon
    Jul 9, 2022 at 12:10
  • 2
    @Anon - there really isn't anything very general - except that the class didn't want to allow automatic conversions via that particular constructor. In some sense, it's really due to the fact that the C++ standard has this somewhat strange rule about implicit conversions, that makes the compiler do things that aren't always aligned with what the creator of the class had in mind. In C#, for example, it's the opposite: by default, no automatic conversion to the class is allowed, and to enable this, you have to use the implicit operator keyword. It's a quirk of C++. Jul 9, 2022 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.