将静态函数声明为友元函数?

3

我在一个名为interface.h的头文件中声明了一个名为MyClass的类,并在file1.cpp中定义了一些静态函数(foobar等)。这些静态函数只在file1.cpp中使用,但它们需要修改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);           
}
想法1: 是否可以将它们声明为MyClass的朋友? 不好的地方: 它们是静态的,并且位于不同的编译单元中。此外,这会让MyClass的用户暴露给它们,而用户并不需要了解它们。 想法2: 没有第二个想法。
相关链接: 是否可能将友元函数声明为静态?

1
你有没有考虑重新设计你的类,使它不需要依赖其他类?需要更多上下文才能给出建议。 - Neil Kirk
在你的例子中,我会简单地为 someVal 编写一个公共 setter,并在 doSomething 中使用它。除非你想防止任何人都能访问该 setter,否则不需要使用 friends。正如 Neil 所说,需要更多信息才能做出决定。 - 463035818_is_not_a_number
foobar函数比演示的更复杂(因此不能将它们改为简单的setter和getter)。重点是要有一些可以修改类但不会使其接口混乱的函数。 - user10607
所以我不想让类的用户知道关于'foo'和'bar'函数,但是我希望'foo'和'bar'可以更改'MyClass'中的任何内容。 - user10607
@RichardHodges 在那个问题中,静态函数和类在同一个文件中。而在我的情况下,它们在两个不同的文件中,因此我无法在类声明之前放置一个前向静态函数声明,因为该函数应该是在另一个文件中静态的,而不是在接口头文件中。 - user10607
显示剩余2条评论
3个回答

3

有点类似:是否可以将友元函数声明为静态的?

个人认为整个 friend 的东西有点像破坏封装的 hack,但你已经提出了一个有效的问题,答案是你可以通过一个 辅助 类来实现你想要的:

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);
}

您真的确定要这样做吗?您确定不想将MyClass的修改器封装在MyClass本身内部吗?


我不是100%确定,但大约有10个函数(即大约有10个mutator),所以我认为如果将它们作为私有方法放在MyClass中,它们只会分散类的用户的注意力。但也许把它们添加为私有成员并不是一个坏主意,因为用户本来就不应该查看私有成员。你明白我的意思吗? - user10607

0

听起来可能很奇怪(并且看起来也是),但实际上你可以读取和写入类/结构的私有成员。

这不太美观,当然也不被鼓励,但是可行的。

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;
}

当我第一次看到它时,我也想:卧槽!


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

你说得对,我本来以为他在讲一些稍微不同的东西。但是,你看,我希望只有函数foobar能够设置someval。在这个解决方案中,任何人都可以调用SetSomeval(),对吧? - user10607
哦,我明白了。那么你可以创建一些函数对象,并将它们设置为 MyClass 的友元来处理这个设置过程。我会修改之前添加的代码,向你展示我所做的。 - Duly Kinsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接