Reputation: 327
I looked around to find the rationale behind the choice made in C++ compiler about what I've called imaginary friends. Unfortunately I didn't find any explanation so I'm asking experts.
I wondering why C++ does not complain about the following code. Classes and method indicate as friends do not exist actually but if you compile the program it will compile and run.
#include <iostream>
class TrueFriend
{
friend class NotExistingClass;
friend class AnotherNotExistingClass;
friend int NotExistingFunc();
public:
void TellAboutYou() { std::cout << "I have a lot of friends" << std::endl; }
};
int main(int argc, char **argv)
{
TrueFriend instance;
instance.TellAboutYou();
return 0;
}
Upvotes: 1
Views: 678
Reputation: 1
I wondering why C++ does not complain about the following code.
You could read some C++ standard like n3337 (or a newer one). That specification does not mention "complaints".
GCC is a compiler implementing more or less C++. You could add your own GCC plugin emitting the diagnostic you want.
Such a GCC plugin would slow down the compilation.
You could try to use the Clang static analyzer. Since it is open source, you are allowed to improve it.
You are designing a GUI library (like FOX). In some cases, some widgets are not implemented (e.G. removed by some #ifdef HAVE_FOO_FEATURE
), but their class needs to be a friend of some existing class. Think for example of some sound related widget: on a PC without speakers, it makes no sense. Or think of some OpenGL related widget on hardware without support for OpenGL. Or of some colored widget on black&white screens....
Or your C++ code has been configured by GNU autoconf. In some cases, some classes would have been disabled.
Or you are writing a library, and have collectively decided with your team that a future C++ class would be named NotExistingClass
and your colleague John in charge of implementing it is on holidays, assigned to more urgent work, or sick.
Likewise, it is reasonable to declare void some_missing_member_function()
inside some class WorkInProgessClass {
... }
and implement that WorkInProgessClass::some_missing_member_function
a few weeks later, when you really need it.
The rationale is that in a project developed by a team, you want to specify (in documents and in stable header files) the common API, and implement it later. A few months later, you could discover that some defined and documented function was not needed at all.
And once Isabel (a developer) in your team is using WorkInProgessClass::some_missing_member_function
she will immediately implement it (otherwise, the linker would complain). Likewise, if she declares an object of a forwarded class NotExistingClass
the linker would emit some error (probably: call/use to undefined NotExistingClass::NotExistingClass()
constructor...)
I love compiling C++ projects (like RefPerSys) with GCC using g++ -Wall -Wextra -g
, and I would be annoyed in getting the warning you are dreaming of.
Another very related example is missing virtual
methods (declared as virtual void foo(void) =0;
in some abstract superclass) with concrete subclasses loaded from plugins at runtime (on Linux, using dlopen(3)...). AFAIK, Qt and FLTK are doing so.
Upvotes: 2
Reputation: 122486
There is no reason to make this code fail to compile. The friend declaration is sufficient to declare the type. And in your code no definition is required. Maybe this would be more clear:
class NotExistingClass;
class AnotherNotExistingClass;
int NotExistingFunc();
class TrueFriend
{
friend NotExistingClass;
friend AnotherNotExistingClass;
friend int NotExistingFunc();
public:
void TellAboutYou() { std::cout << "I have a lot of friends" << std::endl; }
};
with the same effect: The classes and the function are declared but no definition is available. Here you can read about the advantages of forward declaration and why they are needed sometimes: What are forward declarations in C++?
For example consider two types A
and B
that are mutual friends. Thats a scenario where you need a forward delcaration because the headers cannot mutually include each other:
// A.h
class B;
class A{ friend B;};
// B.h
#include "A.h"
class B{ friend A;};
And a shorter way to write A.h
is
class A{ friend class B; };
Now consider you start a new project that uses only A
but not B
. You include A.h
, never use B
and all is fine.
PS: As mentioned in a comment, the friend
is not really essentail for your question. Having types and functions declared but not defined is not that uncommon and sometimes cannot be avoided.
Upvotes: 4