Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declare a member-function of a forward-declared class as friend

Is it possible to declare a member function of a forward-declared class as friend? I am trying to do the following:

class BigComplicatedClass;

class Storage {
   int data_;
public:
   int data() { return data_; }
   // OK, but provides too broad access:
   friend class BigComplicatedClass;
   // ERROR "invalid use of incomplete type":
   friend void BigComplicatedClass::ModifyStorage(); 
};

So the goal is to (i) restrict the friend declaration to a single method, and (ii) not to include the definition of the complicated class to reduce compile time.

One approach might be to add a class acting as an intermediary:

// In Storage.h:
class BigComplicatedClass_Helper;
class Storage {
    // (...)
    friend class BigComplicatedClass_Helper;
};

// In BigComplicatedClass.h:
class BigComplicatedClass_Helper {
     static int &AccessData(Storage &storage) { return storage.data_; }
     friend void BigComplicatedClass::ModifyStorage();
};

However, this seems a bit clumsy... so I assume that there must be a better solution!

like image 524
hrr Avatar asked Jun 10 '11 18:06

hrr


People also ask

How do you declare a friend function in class?

A function or class can't declare itself as a friend of any class. In a class definition, use the friend keyword and the name of a non-member function or other class to grant it access to the private and protected members of your class. In a template definition, a type parameter can be declared as a friend .

Why forward declaration is essential while creating friend function?

Because it wouldn't make sense to be able to declare something in the global namespace if you're inside a namespace {} block. The reason friend class BF; works is that it acts like an implicit forward declaration.

When a function is declared a friend by a class?

A friend function in C++ is defined as a function that can access private, protected and public members of a class. The friend function is declared using the friend keyword inside the body of the class.

How do you forward a declared class method in C++?

In C++, classes and structs can be forward-declared like this: class MyClass; struct MyStruct; In C++, classes can be forward-declared if you only need to use the pointer-to-that-class type (since all object pointers are the same size, and this is what the compiler cares about).


3 Answers

As @Ben says, it's not possible, but you can give specific access just to that member function through a "passkey". It works a bit like the intermediate helper class, but is imho clearer:

// Storage.h
// forward declare the passkey
class StorageDataKey;

class Storage {
   int data_;
public:
   int data() { return data_; }
   // only functions that can pass the key to this function have access
   // and get the data as a reference
   int& data(StorageDataKey const&){ return data_; }
};

// BigComplicatedClass.cpp
#include "BigComplicatedClass.h"
#include "Storage.h"

// define the passkey
class StorageDataKey{
  StorageDataKey(){} // default ctor private
  StorageDataKey(const StorageDataKey&){} // copy ctor private

  // grant access to one method
  friend void BigComplicatedClass::ModifyStorage();
};

void BigComplicatedClass::ModifyStorage(){
  int& data = storage_.data(StorageDataKey());
  // ...
}
like image 172
Xeo Avatar answered Oct 21 '22 21:10

Xeo


No, you can't declare individual member functions as friends until they've been declared. You can only befriend the entire class.

like image 34
Ben Voigt Avatar answered Oct 21 '22 22:10

Ben Voigt


It may or may not be relevant here, but it is useful to remind ourselves that there is a wild world beyond the scope of classes and objects where functions can roam free.

For example, I recently needed to close off a (singleton global static) system error log from a global exception handler based on a port of someone else's code. The normal include file for my error log conflicted with the exception handler code because both wanted to include "windows.h" for reasons I didn't look into. When this and other questions persuaded me I could not make a forward declaration of my ErrorLog class's member functions, what I did was wrap the necessary functions into a global scope function like this:

void WriteUrgentMessageToErrorLog( const char * message )
{
  ErrorLog::LogSimpleMessage( message );
  ErrorLog::FlushAccumulatedMessagesToDisk();
}

Some people are very particular about maintaining the integrity of their class structure at all cost... and seldom acknowledge that applications using those classes are inevitably built on top of something that lacks that structure. But it's out there, and used judiciously, it has its place.

Given the age of this question, I have not looked deeply into its relevance here. All I wanted to share was the opinion that sometimes a simple wrapping mechanism like this is a much cleaner and more readily understood alternative to something that has a lot more subtlety and cleverness about it. Subtlety and cleverness tends to get changed at some later date by someone required to add to it who didn't fully understand it. Before you know it, you have a bug...

like image 1
omatai Avatar answered Oct 21 '22 22:10

omatai