0

My question is very similar to a previously answered question except I'm trying to rewrite the same program using seperate compilation in order to practice proper C++ coding style. I've simplified the program to highlite the problamatic areas.

Currently this program runs fine if I declare the entire class as a friend, but this feels inherently dangerous, giving the entire class friend access.

File Foo.h

#ifndef FOO_H
#define FOO_H

class Foo{
friend class Bar;

public:
    // getX defined in header for simplicity.
    const int &getX() const{
        return x;
    }

private:
    int x = 0;
};

#endif

File Bar.h

#ifndef BAR_H
#define BAR_H

#include "Foo.h"

class Bar{
public:
    void mutateX(Foo &foo);
};

#endif

File Bar.cpp

#include "Bar.h"

void Bar::mutateX(Foo &foo){
    foo.x = 1;
}

I can't wrap my head around how to just make the mutateX member as a friend. Any help will be greatly appreciated!

Here's a tester class main.cpp

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

int main(){
    Foo foo;
    Bar bar;

    std::cout << foo.getX() << std::endl;

    bar.mutateX(foo);
    std::cout << foo.getX() << std::endl;

    return 0;
}
L. Key
  • 53
  • 1
  • 7
  • What's the specific error you're getting with this code? – user0042 Nov 01 '17 at 18:39
  • You can't selectively make member functions be friends. And the general principle you've just stumbled upon is that any friend classes should generally be part of the same module (and header). – StoryTeller - Unslander Monica Nov 01 '17 at 18:39
  • 2
    Don't include "Foo.h" info "Bar.h" - a forward declaration is sufficient, as in `class Foo;` . Then you can include "Bar.h" into "Foo.h" instead, and write `friend void Bar::mutateX(Foo &foo);` – Igor Tandetnik Nov 01 '17 at 18:39
  • BTW, if your idea of separate compilation is that each class should have a completely separate header/implementation file, I think you are misguided. – StoryTeller - Unslander Monica Nov 01 '17 at 18:41
  • 1
    @StoryTeller *"You can't selectively make member functions be friends"* [Can too](http://rextester.com/BYKZ70551) – Igor Tandetnik Nov 01 '17 at 18:42
  • @IgorTandetnik - Fancy that. It's news to me. I need to consult the standard. – StoryTeller - Unslander Monica Nov 01 '17 at 18:43
  • Aha! [Found it](https://timsong-cpp.github.io/cppwp/n4659/class.mfct#6). I'll leave my erroneous comment for its other half. But yes, I was wrong on the first assumption. – StoryTeller - Unslander Monica Nov 01 '17 at 18:48
  • @StoryTeller Interesting, makes sense that friend classes should be part of the same module, I'm still in my early stages of learning C++ and didn't think about it like that. – L. Key Nov 01 '17 at 18:55
  • @IgorTandetnik I tried making the changes you suggested and compiling with: g++ -c -std=c++0x -Wall Bar.cpp But the compiler spat out some errors saying invalid use of Incomplete type 'class Foo' In particular it pointed to the statement foo.x = 1; in Bar.cpp – L. Key Nov 01 '17 at 18:59
  • 1
    @L.Key - Well, it's a step above just programming in C++. It's about designing software modules. Think about it like this: if some entity is a friend of a class, it means that entity participates in implementing/affecting the classes functionality (otherwise, why would it need the access?). It logically follows that they should be part of the same module if encapsulation is a priority. – StoryTeller - Unslander Monica Nov 01 '17 at 18:59
  • 2
    In Bar.cpp you now need to include Foo.h, of course. – Igor Tandetnik Nov 01 '17 at 19:02
  • @IgorTandetnik There we go! That did it haha. So it seems like seperating out the program like this isn't the most elegant way of doing things, and instead I should have made the Bar class be part of the same header as Foo due to their friendly nature? – L. Key Nov 01 '17 at 19:07

0 Answers0