Why does C++ require forward declarations?

A

aleko

This applies equally to function prototypes. Why do we have to tell the
compiler twice? Other modern compiled languages don't have this
requirement.

Just curious,

Aleko
 
V

Victor Bazarov

aleko said:
This applies equally to function prototypes. Why do we have to tell
the compiler twice? Other modern compiled languages don't have this
requirement.

What do you mean by "tell the compiler twice"? When you compile
a module in which the functions are only called and not defined,
what's "twice" about it?

Also, consider that C++ has conversions. If your function, like,
say, myspecialmathfunction, only takes 'double' argument, and you
provide a value of type 'int', how would the compiler know that it
has to convert your 'int' to 'double' when calling that function
unless it has a prototype (declaration) to guide it? And if the
conversion is not applied, a wrong stack frame can be formed and
the behaviour will be incorrect.

And what other languages do not have that requirement? In Pascal
you have to define all functions used *before* they are used. In
C you need to declare them as well. In Fortran... I don't know
about Fortran nowadays, it changed significantly in the decades
passed since I used it last time. Of course there are hundreds of
other languages an in some you probably don't have to declare the
function before it's used, and you probably know since you said so.

V
 
J

James Aguilar

Victor Bazarov said:
And what other languages do not have that requirement? In Pascal
you have to define all functions used *before* they are used. In
C you need to declare them as well. In Fortran... I don't know
about Fortran nowadays, it changed significantly in the decades
passed since I used it last time. Of course there are hundreds of
other languages an in some you probably don't have to declare the
function before it's used, and you probably know since you said so.

Neither Java nor C# have that requirement. Then again, when C++ was being
built, it was harder to write a two-pass compiler, and Java and C# are
simpler languages with simpler grammars. It's just a matter of the compiler
knowing all of the functions available before it tries to link. I mean, the
information is declared somewhere, it's just easier if the compiler only has
to look earlier in a translation unit to find a declaration.

- JFA1
 
E

Evan

It allows the compiler to be a "one pass" compiler. Java and C#
presumably need to read through each input file twice: once to get the
function and method names and once to do the actual compilation.

Note that the compiler needs to know the exact type of the function's
arguments that will be called in order to type check and generate the
appropriate conversions (for instance, int to double promotions) when
they are called. In other words, the compiler needs to know the
signature of the function at the call sites, so it either needs to have
a forward declaration or have read through the rest of the file
already.

(This is not strictly true; it's probably possible to generate a one
pass compiler that will work, but it would require storing the location
of all call sites so that it could go back and insert the proper code.
But this'd be difficult.)

I don't know if compiler implementation difficulty/speed is the
reasoning that led to this requirement, but it is at least a
substantial consequence.
 
A

aleko

I guess I asked more than one question. The original question, about
forward declarations is about situations like this:

struct B; // need to declare B in advance. why?

struct A
{
B* b;
};

struct B
{
....
};

My point is that the forward declaration simply tells the compiler
"I'll tell you about this later." It doesn't give it any concrete
information. It still doesn't know anything about B's structure. The
compiler should be able to insert its own "I'll need to resolve this
later" declaration upon encountering B* b; in A.

I suppose the reason for requiring not-yet declared types to be forward
declared is to make things easier for the compiler. This way, it can
parse the unit only once, without having to go back and forth looking
up types (possibly in other units). Does this make sense?

About the other languages:
Other compiled languages like C#, VB, and Delphi do not require forward
declarations.

I think the issue stems from the fact that C++ does not include type
information in the oject files it produces. This forces the compiler to
rely on header files, which essentially duplicate the function
signatures. That's what I mean by "telling the compiler twice".
 
V

Victor Bazarov

aleko said:
I guess I asked more than one question. The original question, about
forward declarations is about situations like this:

struct B; // need to declare B in advance. why?

Not sure what you want to know. If you're looking for rationale for
requiring every name to be defined before it's used the first time,
then you need to ask in comp.std.c++, that's where the *reasons* for
rules of the language are discussed. If you just want to know why
compilers nowadays complain if youi don't provide a forward-declaration,
then the answer is simple: because the language Standard says that
a program that attempts to use a symbol (name, identifier) that was not
previsously declared, is ill-formed.
struct A
{
B* b;
};

struct B
{
...
};

My point is that the forward declaration simply tells the compiler
"I'll tell you about this later." It doesn't give it any concrete
information.

Oh, yes, it does. It says 'B' is a struct. It's not a function, it's
not an object, it's not a macro, it's not a template.
It still doesn't know anything about B's structure. The
compiler should be able to insert its own "I'll need to resolve this
later" declaration upon encountering B* b; in A.

By requiring the declarations to exist before the first use of any
name, the C++ compilers can be made better than other, multi-pass
compilers.
I suppose the reason for requiring not-yet declared types to be
forward declared is to make things easier for the compiler.

Yes, that's right.
This way,
it can parse the unit only once, without having to go back and forth
looking up types (possibly in other units). Does this make sense?
Absolutely.

About the other languages:
Other compiled languages like C#, VB, and Delphi do not require
forward declarations.

I think the issue stems from the fact that C++ does not include type
information in the oject files it produces. This forces the compiler
to rely on header files, which essentially duplicate the function
signatures. That's what I mean by "telling the compiler twice".

It doesn't duplicate anything. You declare your function once, in the
header or directly in the source. Then you use it. There is no "twice"
there anywhere. The function does not have to be defined in the same
translation unit, and that's what's great about C++. I don't have to
recompile all my units if I change the implementation and do not change
the interface because the modules that call my function do not care how
it's implemented. They only need to know the declaration (name, return
value type, and arguments).

V
 
A

Andrew McDonagh

Victor said:
Not sure what you want to know. If you're looking for rationale for
requiring every name to be defined before it's used the first time,
then you need to ask in comp.std.c++, that's where the *reasons* for
rules of the language are discussed. If you just want to know why
compilers nowadays complain if youi don't provide a forward-declaration,
then the answer is simple: because the language Standard says that
a program that attempts to use a symbol (name, identifier) that was not
previsously declared, is ill-formed.




Oh, yes, it does. It says 'B' is a struct. It's not a function, it's
not an object, it's not a macro, it's not a template.

I'd guess that Aleko was referring to the forward declaration not giving
anything other than the type name 'B' and that its a Struct. It
certainly doesn't give any info on B's contents (functions, etc).
By requiring the declarations to exist before the first use of any
name, the C++ compilers can be made better than other, multi-pass
compilers.




Yes, that's right.

And easier for the developer. Because we don't have to include B's
header file, the compiler won't bother to see if it needs to re-compile
A should we change B. This reduces the compile time coupling between A
and B, thereby speeding up the build time.

Forward declarations should be used when ever a class does not refer to
another class by value, or use the other class inside an inlined function.

e.g.

Not needed:

class A {
...

B* b;
B& anotherB;
}


Needed:

class A {
...

B* b = new B;
}
 
B

beliavsky

Victor said:
And what other languages do not have that requirement? In Pascal
you have to define all functions used *before* they are used. In
C you need to declare them as well. In Fortran... I don't know
about Fortran nowadays, it changed significantly in the decades
passed since I used it last time. Of course there are hundreds of
other languages an in some you probably don't have to declare the
function before it's used, and you probably know since you said so.

In Fortran, if type of a variable or function is not declared, it is
inferred from the first letter, unless the "implicit none" statement is
used, in which case all variables and functions must be declared. Most
Fortran experts agree that all codes should use implicit none.

Fortran 77 did not have function prototypes. Compilers often did not
warn about calling functions and subroutines with mismatched arguments
(although it was not legal Fortran), and one would get unpredictable
results.

In Fortran 90 and later versions, one can use MODULEs to get interface
checking. If file foo.f90 contains

module foo_mod
contains
function foo(x) result(xfoo)
real :: x
real :: xfoo
xfoo = 2*x
end function foo
end module foo_mod

and xfoo.f90 contains

program xmain
use foo_mod, only: foo
integer :: i=2
print*,foo(i)
end program xmain

the error of calling function foo with an integer rather than a real
argument will be detected at compile time, even if foo.f90 and xfoo.f90
are compiled separately. What most compilers do is to create a module
file foo.mod containing information about the procedures in foo.f90
when it is compiled, and this information is used to detect problems
with procedure calls. I think it works pretty well -- one gets
compile-time checking without the need for manually created header
files.
 
T

Taras

Neither Java nor C# have that requirement. Then again, when C++ was
being
built, it was harder to write a two-pass compiler, and Java and C# are
simpler languages with simpler grammars. It's just a matter of the
compiler
knowing all of the functions available before it tries to link. I mean,
the
information is declared somewhere, it's just easier if the compiler only
has
to look earlier in a translation unit to find a declaration.

- JFA1


Neither Java nor C# do not produce binary code, but intermediate
byte code. They are not real compilers but just preparing code
for real time translating (through virtual machine Java or .NET)
 
A

Alf P. Steinbach

* aleko:
This applies equally to function prototypes. Why do we have to tell the
compiler twice? Other modern compiled languages don't have this
requirement.

There are two main reasons.

One, as others have mentioned, is that it makes the compiler's job easier,
and also in some cases makes the knowledgeable programmer's job easier
(the comments about "one-pass" should however be disregarded: that was
an original issue but it's not really meaningful today).

Another is that C++, sadly, lacks support for modular programming. That
is, in standard C++ you can't drag in _compiled_ declarations of something via
some 'import' or 'using' directive. So all that the compiler needs to know
must be supplied as program text.

Given that the language is as it is, though, programmers have found other uses
for declared functions that are actually not implemented anywhere.

One example is to disallow copying objects by declaring a private copy
constructor and assignment operator, another is a declared function that's
only used in sizeof expressions in template-based programming.
 
R

Rolf Magnus

Taras said:
Neither Java nor C# do not produce binary code, but intermediate
byte code.

Neither Java nor C# produce anything. It's the compilers/linkers that do,
and so the type of code that is generated depends on the compiler you use.
The GNU Compiler Colleciton e.g. contains a Java compiler (gcj) that
generates native binary code from Java sources.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top