1

I have a class Foo defined in a header foo.hpp.

class Foo{
... some methods and properties ...
};

Furthermore, I need a function bar() which shall have the following properties:

  • The function bar() shall be defined in the file foo.cpp and its symbols shall not be exported, I want to use internal linkage because bar() is only used in foo.cpp.
  • The function bar() shall have access to the private elements of the function Foo.
  • The function bar() cannot be a member function because I want to pass its address to another function which uses it as a callback.

Is the above possible in C++?

I tried the following: Since the linkage shall be internal, I need to use the static keyword for bar() (see for example here). Furthermore, bar() needs to be declared as a friend of Foo in foo.hpp because it shall have access to its private members. Following this explaination, I need to declare bar() prior to Foo as static. So I adapted this in foo.hpp

static void bar();
class Foo{
... some methods and properties ...
friend void bar();
};

Then foo.cpp would contain the code

static void bar(){
... definition of bar()
}

However, this has the following disadvantages:

  1. In other compilation units that do not involve foo.cpp I get a warning saying something like declared ‘static’ but never defined.

  2. The declaration of bar() is visible to any code that is including foo.hpp. I don't want that, as one could use this to access private members of Foo by redefining bar() in other compilation units.

So this does not work. How would you solve this problem?

NOTE: Of course bar() actually has some parameters that are used to access a specific instance of Foo. I omitted them here.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
phinz
  • 1,225
  • 10
  • 21
  • @LightnessRacesinOrbit I think this should work but then it is visible to all code including `foo.hpp` which is not nice but OK. `bar()` can't be private because I need to pass its address to a third party library https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html . – phinz Mar 16 '18 at 19:08
  • @phinx: In what way is it "visible to all code"? If you are asking how to declare a friend outside of the class definition, so that nobody even knows the friend exists, then no you can't do that. Is that what you're asking? – Lightness Races in Orbit Mar 16 '18 at 19:08
  • @LightnessRacesinOrbit It can be called? Or do I misunderstand something? – phinz Mar 16 '18 at 19:09
  • You can make it `private` and call it only from within the class. You can't give it internal linkage, and it would not make any sense to do so, because a friend declaration would then only be meaningful in one translation unit (and potentially mean something completely different in others). What is the basis for your requirements? It sounds like you're trying to fight the language - is there a reason? – Lightness Races in Orbit Mar 16 '18 at 19:11
  • @LightnessRacesinOrbit Yes that's what I am asking. It would imply an asymmetry between `foo.cpp` and other `cpp` files, indeed. I have to think if it would make sense but I thought so. – phinz Mar 16 '18 at 19:13
  • I think it makes sense if my goal is to ignore encapsulation for a function that is linked internally in a single compilation unit. – phinz Mar 16 '18 at 19:15
  • Personally I think you should abandon your dreams of kafka-esque control over others using your code. Just document that the function shouldn't be called directly and be done with it. – Lightness Races in Orbit Mar 16 '18 at 19:25

3 Answers3

3

Just make bar a static member function of the class. It makes it a global function whose name is scoped to the class (meaning you can use it as a regular function pointer). You can even make it private so only members of your class can call it.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

This should be what you are looking for:

Foo.h

class Foo {
private:
    int f;
public:
    Foo() : f( 5 ) {}
    int fOf() const {
        return f;
    }

    void callModify();

private:
    static friend void modifyFoo(Foo& F); // your bar
};

Foo.cpp

#include "Foo.h"

// your static bar() -- must be defined first
static void modifyFoo( Foo& F ) {
    F.f *= 2;
}

void Foo::callModify() {  // caller to your static bar
    modifyFoo( *this ); // using it in your class
}

main.cpp

#include <iostream>
#include "Foo.h"

int main() {
    Foo foo; 
    std::cout << foo.fOf() << std::endl;
    foo.callModify();
    std::cout << foo.fOf() << std::endl;

    std::cout << "\nPress any key and enter to quit.";
    std::cin.get();
    return 0;
}

If you try to call modifyFoo() out side of Foo.cpp it is not declared nor defined because it is a private static friend of Foo. If you want it visible to the rest of the world then you can make it public in the class. If you are working with inheritance and polymorphism then you can make it protected for all sub classes while keeping it hidden from outside objects.


Edit - According to the nature that the OP wants I had to make a work around as such: It involves the use an internal public struct that contains a static method. The class then has a caller method that will call the modifier, but it will also return the internal struct. This struct is a friend of its parent class.

class Foo {
public:
    struct Modifier {
        friend class Foo;
        static void modify( class Foo& f );
    };
private:
    Modifier modifier;
    int f;

public: 
    Foo : f(5) {}

    int fOf() const {
        return f;
    }

    Foo::Modifier caller() {
        modifier.modify( *this );
        return this->modifier;
    }

private:
    static friend struct FooModifier;
    static friend void Modifier::modifier( Foo& f );
};

#include "Foo.h";

void Foo::Modifier::modify( class Foo& f ) {
    F.f *= 4;
}

#include <iostream>
#include "Foo.h"

int main() {
    Foo foo;
    std::cout << foo.fOf() << std::endl;
    Foo::Modifier m = foo.caller();
    std::cout << foo.fOf() << std::endl;

    m.modifiy( foo );
    std::cout << foo.fOf() << std::endl;

    // you can now pass the struct instance of `m` to your 
    // library which conatiners the modifier function.

    return 0;
}

Output

5
20
80

With this kind of setup you can create an instance of Foo::Modifier since it is public in the Foo's class. Its internal method is static and takes a reference to a specific object of Foo and it is a friend to Foo. This way you can now pass the Foo::Modifier's object m as a struct to your library or you can pass the function address with m.modify( "some relative object of Foo" );

What you are asking for with your strict requirements is not an easy task to achieve.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • Thank you! But I can't pass the address of `callModify()` to a third party library since it is a member function and the friend function is private, so it can't be passed either. – phinz Mar 16 '18 at 19:25
  • @phinz I don't think what you are trying to do will work since the fact the function is static; you want to hide it to outside objects while being able to pass it to an external library. I think that is contradictory. – Francis Cugler Mar 16 '18 at 19:27
  • I want to pass its address to an external library but nobody should know about the function. Basically, I want what @LightnessRacesinOrbit asked about: I want a function that can access private members, that is not a member function, that is only linked internally in the compilation unit of `foo.cpp`, that nobody knows who includes the header but that can be exposed to an external library if I want to (which I would only do in `foo.cpp`). – phinz Mar 16 '18 at 19:32
  • @phinz I think I might of worked something out, but it required a few extra steps; check out the edit to the end of my original post. – Francis Cugler Mar 16 '18 at 19:45
  • I don't really understand why `modify` is linked internally in the compilation unit of `foo.cpp` (static has a different meaning here: a global function that can access members) and why someone including `foo.h` does not see it (he can see the source of the header). Maybe my question was not clearly specified and the title did't fully capture the problem, sorry. You still got my vote. – phinz Mar 17 '18 at 08:50
0

What I want does not seem to be possible. It seems that the only options are the following:

  1. Do not declare the function bar() in foo.hpp as a friend, only declare and define it as static in foo.cpp and use dirty tricks with pointers and casts to change private elements of an instance of Foo. I don't like this one.
  2. Drop the requirement that bar() should not be visible for code that is including foo.hpp and use NathanOliver's answer.
  3. Drop the requirement that bar() can access private members of an instance of Foo and use an anonymous namespace in foo.cpp where we derive a subclass subFoo of Foo (do not add new members) and define bar() as its friend function in the anonymous namespace and do not declare it in the header foo.hpp. It can then access at least protected members of Foo if we cast an instance of Foo to subFoo in bar().

I will use the third option.

phinz
  • 1,225
  • 10
  • 21