3

I have a class MyClass declaration in a header file interface.h and some static functions (foo and bar and a few more) in file1.cpp. The static functions are only used inside file1.cpp but they need to modify private/protected members of MyClass`.

// in "interface.h"
class MyClass {
// maybe declare as friend?
// friend static void foo(MyClass &ref);
private:
    double someval;
}

// in "file1.cpp"
static void foo(MyClass &ref) {
    ref.someval = 41.0;
}
static void bar(MyClass &ref) {
    ref.someval = 0.42;
}

// function that uses foo/bar
void doSomething(MyClass &ref) {
    foo(ref);           
}

Idea 1: Somehow declare them as friends of MyClass?

Why its not good: They are static AND are in a different compilation unit. Besides that would expose them to the user of MyClass who does not need to know anything about them.

Idea 2: Don't have idea 2.

Sort of linked: Is it possible to declare a friend function as static?

Community
  • 1
  • 1
user10607
  • 3,011
  • 4
  • 24
  • 31
  • 1
    Have you considered redesigning your class so that it doesn't need friends? Need more context to advise here. – Neil Kirk Apr 01 '15 at 12:57
  • In your example I would simply write a public setter for `someVal` and use this in `doSomething`. No need for friends unless you want to prevent that anybody can access the setter. As Neil said, more information is needed to decide. – 463035818_is_not_an_ai Apr 01 '15 at 13:04
  • The `foo` and `bar` functions are more complex than demonstrated (so they can not be changed to simple setters and getters) The point was to have some functions that could modify the class, but that would not clutter its interface. – user10607 Apr 01 '15 at 13:11
  • So I don't want users of the class to know about the `foo` and `bar` functions, but I want `foo` and `bar` to change anything in `MyClass`. – user10607 Apr 01 '15 at 13:13
  • The link to the related question actually contains the answer to your question. – Richard Hodges Apr 01 '15 at 13:35
  • @RichardHodges In that question the static function and the class are in the same file. In my situation they are in two different files, so I can not put a forward **static** function declaration before the class declaration, because the function is supposed to be static in another file, not in the interface header. – user10607 Apr 01 '15 at 14:24
  • It seems to me that you have not sufficiently separated responsibilities in your solution. The static function must be called by something. That something should probably just be a friend (or a member) of the class. – Richard Hodges Apr 01 '15 at 17:21

3 Answers3

3

Sort of linked: Is it possible to declare a friend function as static?

Personally I find the whole friend thing a bit of a hack that breaks encapsulation but you've asked a valid question and the answer is that you can achieve what you want with a helper class:

file1.h

class MyClass {
private:
  double someval;

  friend class MyClassHelper;
};

file1.cpp

#include "file1.h"


struct MyClassHelper {
  static void mutateMyClass(MyClass& ref) {
    ref.someval=42;
  }
};


// in "file1.cpp"
static void foo(MyClass &ref) {
  MyClassHelper::mutateMyClass(ref);
}

Are you really sure you want to do it like this? Are you sure you don't want to encapsulate MyClass's mutators inside MyClass itself?

Andy Brown
  • 11,766
  • 2
  • 42
  • 61
  • I am not 100% sure)) But there are around 10 functions (that is around 10 mutators), so I thought that if I put them in the `MyClass` as private methods they would just distract the user of the class. **But** maybe its not such a bad idea to just add them as private, since the users should not look at private members anyway. Do you see what I mean? – user10607 Apr 01 '15 at 13:51
0

As weird as it may sound (and look), you can actually read & write private members of a class / struct.

It's not pretty, and certainly not encouraged, but doable.

template<typename T>
struct invisible
{
    static typename T::type value;
};

template<typename T>
typename T::type invisible<T>::value;

template<typename T, typename T::type P>
class construct_invisible
{
    construct_invisible(){ invisible<T>::value = P; }
    static const construct_invisible instance;
};

template<typename T, typename T::type P>
const construct_invisible<T, P> construct_invisible<T, P>::instance;

struct MyClass_someval{ typedef double MyClass::*type; };
template class construct_invisible<MyClass_someval, &MyClass::someval>;

static void foo(MyClass &ref) {
    ref.*invisible<MyClass_someval>::value = 41.0;
}

When I first saw it I also thought: HOLY S***!

ArnonZ
  • 3,822
  • 4
  • 32
  • 42
0
// in "interface.h"
class MyClass {
  // maybe declare as friend?
  // friend static void foo(MyClass &ref);
public:

  friend class SetSomevalClass; // make the classes friends

private:

  double someval;
};

class SetSomevalClass // functor class(or function class)
{
public:
  double operator()(MyClass n, double data) // this could have been void
  {
    n.someval = data; //set somevalue to data
    return n.someval; //return somevalue
    // return is solely used to show result in foo() and bar()
  }
};


// in "file1.cpp"
static void foo(MyClass &ref)
{
  SetSomevalClass s; //create functor object

  //s(ref, 40);
  //this would be the end of the foo function(uncommented) if we did        not want to show the result

  std::cout << "foo()" << s(ref, 40) << std::endl;
  //simply to show result

}
static void bar(MyClass &ref)
{
  SetSomevalClass s;

  //s(ref,2);

  //this would be the end of the foo function(uncommented) if we did not want to show the result

  std::cout << "bar()" << s(ref, 2) << std::endl;
}

// function that uses foo/bar
void doSomething(MyClass &ref) //calls both foo() and bar()
{
  foo(ref);
  bar(ref);

}

int main()
{
  MyClass s;
  doSomething(s); 
}// end main
Duly Kinsky
  • 996
  • 9
  • 11
  • You are right I though he was talking about somethign slightly different. But, you see, I want only functions `foo` and `bar` to be able to set `someval`. In this solution, anybody can call `SetSomeval()` right? – user10607 Apr 01 '15 at 13:55
  • oh I see. Well you could create functors that are befriended to MyClass to handle the setting. I will modify the code I added earlier to show you what I did – Duly Kinsky Apr 01 '15 at 15:49