In a project I read, there are two header files and two declarations for the same class. One is used by programs that use this library, serving as an interface. Another is used by the library itself.The interface header file is simpler. It doesn't contain private members and has less methods. Even methods that appear in both files may not appear in the same order. I wonder if it is legal to have 2 header files for the same class? If it is not, what are the possible consequences?
-
6That is a ODR violation – NathanOliver May 15 '22 at 01:45
-
2All questions here should have all relevant information ***in the question itself as plain text***. Links can stop working at any time making questions meaningless. Code, data, or errors shown as images cannot be copy/pasted; or edited or compiled for further research and investigation. Can you [edit] this question, removing and replacing all links and images with all relevant information as plain text? All code must meet all requirements of a [mre]. You'll find many other questions here, with a [mre], in plain text. Please use them as an example for how your question should look. – Sam Varshavchik May 15 '22 at 01:55
-
1If two class definitions are *identical* in both headers (in the sense of exactly the same set of tokens) there is no ODR violation. In your case, the two class definitions declare a different set of member functions, so there is an ODR violation if the two headers are included by any combination of source files in your project. No diagnostic is required, but that doesn't mean the code has well defined behaviour. One reason class definitions are placed in headers is to avoid this sort of thing - but that relies on the single header that defines the class being included consistently. – Peter May 15 '22 at 02:19
-
1Programs that want to do this kind of thing are likely to want/need the pImpl idiom anyway; they could then just have the differently-named interfaces all rely on the same private implementation class, which implements the common superset of the interfaces. – Karl Knechtel May 15 '22 at 02:22
-
A legal (but very limiting) way to do this is to make the classes *layout compatible*: https://en.cppreference.com/w/cpp/language/data_members#Standard_layout Another way is to give the user only access to pointers of that class (e.g. by factory functions) so that every access to member variables or virtual member functions of the class is done by external code. (Not sure, whether calling non-virtual member functions of incompletely defined classes would be legal in the standard, but at least that could be mostly save.) PImpl is the cleaner alternative. Or free functions getting a pointer. – Sebastian May 15 '22 at 04:11
-
@Sebastian not sure that it helps considering the requirement of same access control for the compatible layout to work (second paragraph of your link). Here more explanations about layouts involving public and private access control: https://stackoverflow.com/a/36149568/3723423 – Christophe May 15 '22 at 19:20
-
@Christophe You are referring to the first way described in my comment. As I wrote *very limiting* ... – Sebastian May 15 '22 at 20:33
-
@Sebastian yes indeed: just the first one. – Christophe May 16 '22 at 05:04
1 Answers
In short
This is not legal at all. Depending of what's in the private part that is committed, it might work on some implementations, but it might very well fail at the first change or new release of the compiler. Just don't. There are better ways to achieve the intended objectives.
Some more explanations
Why it's not legal?
It's the One Definition Rule (ODR). It's defined in the standard, in a long section [basic.def.odr]
. In summary, it is possible to have multiple definition of the same class in different compilation units (e.g. your code, and the library's code), but only if it's exactly the same definition. This requires that it's exactly the same sequence of tokens that are used for the two definitions, which is clearly not the case if you leave out the private members. (Note that there are additional requirements as well, but the first one is already broken, so I short-circuit).
Why does it work in practice in some cases even if not legal?
It's purely implementation dependent luck. I will not develop this topic, in order not to encourage dangerous behavior.
What alternatives
Just use the same definition of the class everywhere. Private members are private, so what's the risk of leaving them where they were ?
Ok, sometimes the definition of private members would require to disclose also private types, end as a chain reaction, much too much. In this case, you may think of:
- The simple opaque pointer technique, which uses a pointer to a private implementation class, whose type is declared but that is not defined in the compilation units that do not need to know.
- The more elaborate bridge pattern, which allows to build class hierarchies for an abstraction, and class hierarchies with the implementation. It can be used in a similar way than the opaque pointer, but would allow for different kind of private implementation classes (it's a complex pattern, and it's an overkill if it's just for hiding private details).

- 68,716
- 7
- 72
- 138