473,383 Members | 1,725 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

A question about One Definition Rule

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!
Jul 22 '05 #1
7 2383
CoolPint wrote:
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.

--
Russell Hanneken
rg********@pobox.com
Remove the 'g' from my address to send me mail.

Jul 22 '05 #2
> 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
Jul 22 '05 #3
je******@comcast.net (Jeff) wrote in message news:<a8*************************@posting.google.c om>...
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.


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.
--
Gary
Jul 22 '05 #4
Russell Hanneken <rg********@pobox.com> wrote in message news:<Fs******************@newsread2.news.pas.eart hlink.net>...
CoolPint wrote:
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.


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::out2( )
{
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::out1( )
{
cout << "x = " << x << " from out1." << endl;
x++;
}

Which works just fine. I tried to include only what each TU needed in
the class declaration.
--
Gary
Jul 22 '05 #5
je******@comcast.net (Jeff) wrote in message news:<a8*************************@posting.google.c om>...
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!
Jul 22 '05 #6

"Gary" <gl*******@comcast.net> wrote in message
news:39**************************@posting.google.c om...

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::out2( )
{
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::out1( )
{
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?

--
Russell Hanneken
rg********@pobox.com
Remove the 'g' from my address to send me mail.
Jul 22 '05 #7
co******@yahoo.co.uk (CoolPint) wrote in message news:<15**************************@posting.google. com>...
je******@comcast.net (Jeff) wrote in message news:<a8*************************@posting.google.c om>...
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!

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.
--
Gary
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

220
by: Brandon J. Van Every | last post by:
What's better about Ruby than Python? I'm sure there's something. What is it? This is not a troll. I'm language shopping and I want people's answers. I don't know beans about Ruby or have...
13
by: Vincezo Ciaschini | last post by:
Supposing you have the following declaration in a header file: -- head.h -- struct s { int c; char v; #if defined(__cplusplus) s(); s(double); method1(int);
28
by: Wonder | last post by:
Hello, I'm confused by the pointer definition such as int *(p); It seems if the parenthesis close p, it defines only 3 integers. The star is just useless. It can be showed by my program: ...
3
by: Ninan | last post by:
I am using gcc compiler gcc B.o Main.o -lMyLib //A.h class A { public: A(); void abc ();
2
by: The Cool Giraffe | last post by:
I was told to use the following scheme. // Some.h class Some { bool doSome ();}; // Some.cpp #include "Some.h" bool Some::doSome () {return true;}
17
by: Jess | last post by:
Hello, If I have a class that has virtual but non-pure declarations, like class A{ virtual void f(); }; Then is A still an abstract class? Do I have to have "virtual void f() = 0;"...
5
by: gw7rib | last post by:
I was having linking errors when I put: const LPCTSTR Main_window_name = _TEXT("Thingy_main_window"); in one file and extern const LPCTSTR Main_window_name; in another. I've since...
23
by: Tony Johansson | last post by:
Hello! I just wonder what is the point of having the reader variable declared as TextReader in the snippet below.. Is it because of using the polymorfism on the reader variable perhaps. using...
49
by: Pilcrow | last post by:
In the code below, can someone explain why the asterisks seem to be required on the line labelled 'A' and forbidden on the line labelled 'B'? Thanks in advance for the help....
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.