1

According to the one definition rule, class and struct definitions must not repeat in a single translation unit.

But then why is the case that they are allowed to be repeated in multiple translation units, if they are in reality definitions. Why doesnt the linker throw a multiple definition error in that case ?

E.g. - Following should throw a multiple definition error by the same logic

test.h

#ifndef TEST
#define TEST

class s {
  int a;
  int b;
};

#endif

test1.cpp

#include "test.h"

int main() {}

test2.cpp

#include "test.h"
Gaurav Pant
  • 962
  • 10
  • 30
  • Information here: https://stackoverflow.com/questions/6379422/c-multiple-classes-with-same-name Not sure if it is an exact answer – Ray Toal Apr 03 '19 at 04:16
  • Because these are not definitions but declarations, and the linker doesn't see declarations. – user207421 Apr 03 '19 at 06:24
  • @user207421 I am pretty much sure, the standard says otherwise – Gaurav Pant Apr 03 '19 at 06:37
  • Then you would be wrong. Your .h file contains a class declaration. It doesn't contain any definitions, and in fact there is nothing in it that would ever need a definition, i.e. generate any object code, so it will never come to the attention of the linker. There is a one-definition rule, and the only rational explanation of your failure to violate it is that there are no definitions here. If you think the C++ standard says otherwise please cite chapter and verse. – user207421 Apr 03 '19 at 08:02
  • 1
    @user207421, quote C++ 3.1/2 **A declaration is a definition unless it [...] is a class name declaration [...].** – Gaurav Pant Apr 03 '19 at 11:53

3 Answers3

8

But then why is the case that they are allowed to be repeated in multiple translation units, if they are in reality definitions.

At the language level, the answer is simply: because the standard says so, specifically in [basic.def.odr]/6

There can be more than one definition of a class type, enumeration type, inline function with external linkage ([dcl.inline]), inline variable with external linkage ([dcl.inline]), class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. […]

Of course, there are reasons for why the rules of the language are the way they are. At the implementation level, the definition of a class just tells the compiler how code that operates on objects of the respective class type has to conduct business, e.g., where in an object members are located and so on. But a class definition doesn't really generate code by itself. It is necessary that the compiler gets to see a definition of every class type in each translation unit where that class is used so that it can generate the right code for each translation unit independently. It is also necessary that the definition of a class type be the same in every translation unit so that the code generated for each translation unit is compatible with the code generated for all the other translation units.

Why doesnt the linker throw a multiple definition error in that case ?

The linker working at the symbol level in the end only gets to see generated object code. And class definitions don't have an explicit representation at the machine code level. The concept of a class doesn't really exist at that level. They are found in the way the code operates rather than in the code directly. They live between the lines of assembly if you want…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
3

Class definitions contain two parts in a broad sense -- member variable definitions and member function declarations/defintions. (I realize classes may contain nested types, enums, typedefs, etc.)

Member variable definitions provide a template for creating objects, they are not executable code. Hence, having them defined in multiple files should not be a problem.

Member function declarations are exactly that -- declarations. Once again, they are not executable code. Hence, having them defined in multiple files should not be a problem.

Member function definitions, if they are inline, are treated just like any other inline function. Having them defined in multiple files should not be a problem.

Member function definitions, if they are not inline, will cause a problem if they are defined in a .h files and the .h file is #included in multiple translation units.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

The C language is designed to be usable on platforms with very primitive linkers, placing minimal demands upon them. The C++ language demands more. For a platform to practically support linking of separately-compiled modules written in C++, its linker must at minimum support weak and partial symbols or other similar constructs. If two or more weak definitions exist for a weak symbol, and there is no strong definition, the linker will treat one of the weak symbols (chosen arbitrarily) as strong and ignore the rest. If two or more partial definitions exist for a symbol, the associated data will be concatenated in generally-arbitrary order, and all references to the symbol will identify the start of the concatenated blob. Typically, there will also be a means of generating a symbol with a related name that identifies the length or ending address of the blob.

A language that requires linkers to have such features can offer better semantics to programmers than one which must be usable even with even a minimalist linker.

supercat
  • 77,689
  • 9
  • 166
  • 211