MadBlack
MadBlack

Reputation: 327

C++ and incomplete friend classes

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

Answers (2)

I wondering why C++ does not complain about the following code.

C++ is a programming language specification.

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.

BTW, there is a good case when non-existing friend classes are needed.

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.

public APIs should be more stable than code implementing them.

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

463035818_is_not_an_ai
463035818_is_not_an_ai

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

Related Questions