The multiple-declaration problem

I'm a bit confused about the multiple-declaration problem. does it still exist??

According to Bruce Ecker, it's not allowed to declare a function multiple times. However, whatever I try, I never get the "multiple declaration error" yet I do receive "multiple definition errors" from time to time. (using the Xcode compiler in MacOSX)

My question:
Did the rules regarding multiple declarations change? The book is 12 years old so I can imagine the claim is no longer true.

This is the code that is supposed to 'not work':
1
2
//header.h
void n();


1
2
//header2.h
void n(); // <-- shouldn't this be illegal? 


1
2
3
4
5
//File.cpp
#include "Header.h"
#include "Header2.h"

void n() {};


yet it compiles without a problem. Did the rules change over the years?

N.B.
only if I add a definition in both headers will it trigger an error. As expected it will give me a redefinition error.

TL:DR
Is it now allowed to have multiple-declarations, as long as it's not multiple-definitions and was this different in the year 2000 where it was illegal to have multiple declarations?
This is a legal program and it should compile just fine.
This 'feature' is called function forward declaration.

For eg. you may have:

1
2
3
4
5
6
7
8
9
10
11
void f();

int main()
{
f();
}

f()
{
//body
}


So you tell the compiler that f is a valid identifier, a function, but it's defined somewhere else, then you use it in main() and then the compiler also finds the definition. Among other things it's useful for defining mutual recursive functions (functions that are defined in terms of each other):

1
2
3
4
5
6
7
8
9
10
11
12
13
int first(int x) {
   if (x == 0)
      return 1;
 
   return second(x-1); //forward reference to second
}
 
int second(int x) {
   if (x == 0)
      return 0;
 
   return first(x-1);
}


(code from: http://en.wikipedia.org/wiki/Forward_declaration )

first() needs second() and second() needs first(). When the compiler reaches second(), first() is already defined so no problem. But before that, when it first reaches first(), second() is not defined nor declared, so it will give an error ... 'second': identifier not found.
So you just have to put the declaration of second() in front of first() and it will work just fine.

1
2
3
4
5
int second(...);
int first()
{...second()...}
....
int second(...){...}


Just another cool example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool odd(int number);

bool even(int number)
{
    if (number == 0)
        return true;
    else
        return odd(abs(number)-1);
}

bool odd(int number)
{
    if (number == 0)
        return false;
    else
        return even(abs(number)-1);
}


Forward declaration is also used when working with classes (Class A uses an object of type B, and class B uses an object of type A....so, just declare class B; before class A definition and it's ok).

Cheers!
I see, I was aware of forward declaration and for some reason never linked it with headers. I suppose headers confuse me a lot.

Would you have any clue what problem the book is referring too? this is what it says:

The compiler considers the redeclaration of a structure (this includes both structs and classes) to be an error, since it would otherwise allow you to use the same name for different types.


yet if I put a "struct P" in both headers, it will combine fine. So just declaring it doesn't seem to be a problem.
However, defining it in both headers gives an error:
"struct P {}; "

so this leaves me clueless what he means with "multiple-declaration problem". Isn't this a multi-definition problem?

Last edited on
There is the one definition rule in C++. So any function with external linkage which is not an inline function or a function template shall be defined only once. However it may be declared several times.

For example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

void f( int x, int y );

int main()
{
   f( 10, 20 );

   void f( int x, int y = 20 );
   f( 10 );

   void f( int x = 10, int y );

   f();

   return 0;
}

void f( int x, int y )
{
   std::cout << "x = " << x << ", y = " << y << std::endl;
}
I found out about the one definition rule in C++ but not about the one-declaration rule. It's invalid right, there is no such thing?

so this text:
The compiler considers the redeclaration of a structure (this includes both structs and classes) to be an error, since it would otherwise allow you to use the same name for different types.

Should read
The compiler considers the redefinition of a structure (this includes both structs and classes) to be an error, since it would otherwise allow you to use the same name for different types.

Right?
He said about redeclaration of a structure as redeclaration it as another type. Though in any case it is not correct. You may declare the same name as a structure name and at the same time as a function or object name. In this case the function or object name hides the structure name.
For example, this is correct code

1
2
3
4
5
6
7
8
9
10
#include <iostream>

struct A {};
int A = 10;

int main()
{
   std:;cout << "int A = " << A << std::endl;
   struct A a;
}


Here the name A is declared twice as two different entities.
Last edited on
If you don't intend to become a C++ guru in a couple of days and hack each and every word in a C++ cookbook (which may contain errors or vague phrases) just get over it because it's a minor thing.

Headers... :

1
2
3
4
5
//a.h
void f();
void g();
int h();
class w{};


1
2
3
//b.h
class w1{};
int a;


1
2
3
4
5
6
7
8
9
10
//main.cpp
#include "b.h"
#include "a.h"

int c;

int main()
{
//....
}


main.cpp will be the first file to be processed by the compiler, because it has the main() function which is the entry point of the application. It starts from top. include a.h -> it will include all that's there, verbatim! same for b.h.
The compiler sees the 3 pieces of code above like this (one big program):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//main.cpp

//b.h
class w1{};
int a;

//a.h
void f();
void g();
int h();
class w{};

int c;

int main()
{
//....
}


... in the exact same order we included them. b.h and then a.h.

When you have a.h and a.cpp(which holds the definitions for the things declared in a.h) then a.h and a.cpp make a translation unit and it will result in an a.obj on disk which will be later used when linking. This is done by compilers for optimization. Let's say you have 20 translation units in a project (a.h a.cpp, b.h b.cpp, c.h c.cpp and so on) and you use all those in main.cpp. You build once and objects are created: a.obj, b.obj, c.obj etc. Then you modify for example c.cpp. When you build again, only the c translation unit will be re-built into c.obj and also main.obj because it uses things from c (and any other unit which uses c) and that's it. The other units are already in .obj files and are used as they are at linking. So no need to rebuild all 20 units but just 2 (c and main).

PS: .obj is the naming done by Visual C++, other compilers name them differently (gcc objects are .o, and so on).

Regards,
Last edited on
Thanks, those last two explanations did the trick, I finally get it now. Thanks a ton for your time.
Topic archived. No new replies allowed.