A question about One Definition Rule

C

CoolPint

I read that there has to be only one definition of classes, functions,
etc. in a project.

I just realized I might have broken the rule by defining the exception
classes in the header file. But my linker does NOT complain. For
example,

Let's say I have a header file somewhat like below
// MyClass.h
class MyClassException1 {};
class MyClassException2 {};

class MyClass {
public:
// blah blah blah
private:
// blah blah blah
};
and a corresponding translate unit MyClass.cpp containing definitions
of member functions.

If I have a project with many translation units all including
"MyClass.h", wouldn't this be breaking the one definition rule since
each unit would be defining MyClassException1 and MyClassException2
classes again and again?
Why isn't my linker saying anything?

In a situation like this, should I have a separate translation unit
and the header file for the exception classes to make sure I don't
break ODR?

// MyClassException.h
class MyClassException1;
class MyClassException2;

// MyClassException.cpp
class MyClassException1 { };
class MyClassException2 { };

To be honest, I feel rather reluctant to create another set of a
header and translation unit for simple things like above. But if it's
required to make sure I don't break ODR, then I have no choice, do I?

Please help understand better. Thanks in Advance!
 
R

Russell Hanneken

CoolPint said:
I read that there has to be only one definition of classes, functions,
etc. in a project.

The "one definition rule" is not nearly so straightforward.
Let's say I have a header file somewhat like below
// MyClass.h
class MyClassException1 {};
class MyClassException2 {};

class MyClass {
public:
// blah blah blah
private:
// blah blah blah
};
and a corresponding translate unit MyClass.cpp containing definitions
of member functions.

In a situation like this, should I have a separate translation unit
and the header file for the exception classes to make sure I don't
break ODR?

// MyClassException.h
class MyClassException1;
class MyClassException2;

// MyClassException.cpp
class MyClassException1 { };
class MyClassException2 { };

If the one definition rule really said you couldn't define a class more
than once in a program, you would also have to put the definition of
MyClass in a separate translation unit, and forward declare it in the
MyClass.h header. But that would be a problem; sometimes more than just
a forward declaration of a class needs to be visible in a translation
unit where the class is used.

Actually, the one definition rule says a class can be defined in more
than one translation unit, provided that

1. The class is defined no more than once in a translation unit.
2. The definitions consist of exactly the same tokens.
3. The tokens mean the same thing in each definition.
 
J

Jeff

I just realized I might have broken the rule by defining the exception
classes in the header file. But my linker does NOT complain.

The class definitions all have to be identical. As long as that's
true (e.g. because they all come from the same included file), you're
okay.

Happy hacking,
Jeff
 
G

Gary

The class definitions all have to be identical. As long as that's
true (e.g. because they all come from the same included file), you're
okay.

I'm glad the OP is now okay. But your answer threw me off.

Are you actually talking about a class definition, meaning the code of
the functions? Or do you mean a class declaration, which just
indicates what identifiers in the class refer to?

I have been teaching that the description of a class, giving its
contents by name, does not cause allocation of memory. I've called it
a declaration, only.
I'm aware that a declaration can also be a definiton (as in int x;
which declares x to be an int, and also allocates memory for an int
called x), but I'm under the impression that declaration of classes
does not also define unless code is contained in it. The actual
allocation of memory takes place when an object of the class type is
created.
These are such slippery terms, I'd like your input on this. Thanks.
 
G

Gary

Russell Hanneken said:
The "one definition rule" is not nearly so straightforward.


If the one definition rule really said you couldn't define a class more
than once in a program, you would also have to put the definition of
MyClass in a separate translation unit, and forward declare it in the
MyClass.h header. But that would be a problem; sometimes more than just
a forward declaration of a class needs to be visible in a translation
unit where the class is used.

Actually, the one definition rule says a class can be defined in more
than one translation unit, provided that

1. The class is defined no more than once in a translation unit.
2. The definitions consist of exactly the same tokens.
3. The tokens mean the same thing in each definition.

What do you make of this:
File 1-------------
class Test
{
public:
void out1( );
void out2( );
Test(int);
};

int main( )
{
Test testA(5);
testA.out2( );
testA.out1( );
testA.out1( );
testA.out2( );

return 0;
}

File 2 -----------
#include<iostream>
using namespace std;

class Test
{
public:
Test(int);
void out2( );
private:
int x;
};

void Test::eek:ut2( )
{
cout << "x = " << x << " from out2." << endl;
++x;
}

Test::Test(int z):x(z){};

File 3-----------
#include<iostream>
using namespace std;

class Test
{
int x;
public:
void out1( );
};

void Test::eek:ut1( )
{
cout << "x = " << x << " from out1." << endl;
x++;
}

Which works just fine. I tried to include only what each TU needed in
the class declaration.
 
C

CoolPint

The class definitions all have to be identical. As long as that's
true (e.g. because they all come from the same included file), you're
okay.

Thank you for answering my question. I now understand why my linker
didn't complain.

Just out of curiosity....
What would happen if the class definitions were not identical?
Would the linker detect the problem and complain as a standard or
would it be
another case of "undefined behaviour" and "implementation dependent"
problems?

TIA!
 
R

Russell Hanneken

Gary said:
What do you make of this:
File 1-------------
class Test
{
public:
void out1( );
void out2( );
Test(int);
};

int main( )
{
Test testA(5);
testA.out2( );
testA.out1( );
testA.out1( );
testA.out2( );

return 0;
}

File 2 -----------
#include<iostream>
using namespace std;

class Test
{
public:
Test(int);
void out2( );
private:
int x;
};

void Test::eek:ut2( )
{
cout << "x = " << x << " from out2." << endl;
++x;
}

Test::Test(int z):x(z){};

File 3-----------
#include<iostream>
using namespace std;

class Test
{
int x;
public:
void out1( );
};

void Test::eek:ut1( )
{
cout << "x = " << x << " from out1." << endl;
x++;
}

Which works just fine. I tried to include only what each TU needed in
the class declaration.

Well, this is interesting. As far as I can tell, your code violates the One
Definition Rule, but I tested it with three compilers, and each of them
built the program without complaint, even when I asked the compilers to
enforce strict ANSI compliance.

As I read the standard, your code should result in undefined behavior, so I
guess my compilers aren't exactly wrong. Still, I'm surprised by the lack
of error messages. Maybe it's too difficult for compilers to catch the
problem? Can anyone comment?
 
G

Gary

Thank you for answering my question. I now understand why my linker
didn't complain.

Just out of curiosity....
What would happen if the class definitions were not identical?
Would the linker detect the problem and complain as a standard or
would it be
another case of "undefined behaviour" and "implementation dependent"
problems?

TIA!
I'm sorry if this post duplicates another. I'm working through Google
and it seems to be super slow getting posts into the ng.

The compiler only needs the declarations that the translation unit
uses so that type checking and correct parameter list and defaults can
be determined. It assumes that the actual code will be found somewhere
later during the linkage editing. I have posted an example of this
which I hope shows up soon. I'll be back on my home server tomorrow.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,147
Messages
2,570,837
Members
47,385
Latest member
Joneswilliam01

Latest Threads

Top