【问题标题】:Declare static functions as friend function?将静态函数声明为友元函数?
【发布时间】:2015-04-01 12:55:43
【问题描述】:

我在头文件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:没有想法 2。

链接类型:Is it possible to declare a friend function as static?

【问题讨论】:

  • 您是否考虑过重新设计您的班级以使其不再需要朋友?需要更多背景信息在这里提供建议。
  • 在您的示例中,我将简单地为someVal 编写一个公共设置器并在doSomething 中使用它。除非您想防止任何人都可以访问设置器,否则不需要朋友。正如尼尔所说,需要更多信息才能做出决定。
  • foobar 函数比演示的更复杂(因此它们不能更改为简单的 setter 和 getter)关键是要有一些可以修改类的函数,但是不会弄乱它的界面。
  • 所以我不希望班级的用户知道foobar 函数,但我希望foobar 更改MyClass 中的任何内容。
  • 相关问题的链接实际上包含您问题的答案。

标签: c++


【解决方案1】:

某种链接:是否可以将友元函数声明为静态的?

就我个人而言,我发现整个 friend 有点破坏封装性,但您提出了一个有效的问题,答案是您可以使用 helper 类实现您想要的:

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 个变异函数),所以我认为如果我将它们作为私有方法放在 MyClass 中,它们只会分散注意力类的用户。 但是将它们添加为私有成员可能不是一个坏主意,因为用户无论如何都不应该查看私有成员。你明白我的意思吗?
【解决方案2】:

尽管听起来(和看起来)很奇怪,但您实际上可以读写类/结构的私有成员。

这不漂亮,当然也不鼓励,但可行。

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

当我第一次看到它时,我还想:HOLY S***!

【讨论】:

    【解决方案3】:
    // 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() 对吗?
    • 哦,我明白了。好吧,您可以创建与 MyClass 友好的函子来处理设置。我将修改我之前添加的代码,向您展示我所做的
    猜你喜欢
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多