我可以使用从外部看不到但在标题中未定义的静态友元函数吗?

时间:2018-03-16 18:53:40

标签: c++ linkage

我在标题Foo中定义了一个类foo.hpp

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

此外,我需要一个函数bar(),它具有以下属性:

  • 函数bar()应在文件foo.cpp中定义,其符号不得导出,我想使用内部链接,因为bar()仅用于foo.cpp
  • 函数bar()可以访问函数Foo的私有元素。
  • 函数bar()不能是成员函数,因为我想将其地址传递给另一个使用它作为回调的函数。

C ++中是否可以实现上述目标?

我尝试了以下操作:由于链接应该是内部的,我需要使用static bar()关键字bar()friend。此外,Foo需要在foo.hpp中声明为bar() Foo,因为它可以访问其私人成员。在see for example here之后,我需要将foo.hpp 之前的声明为static void bar(); class Foo{ ... some methods and properties ... friend void bar(); };  静止的。所以我在foo.cpp

中对此进行了调整
static void bar(){
... definition of bar()
}

然后foo.cpp将包含代码

declared ‘static’ but never defined

然而,这有以下缺点:

  1. 在其他不涉及bar()的编译单元中,我得到了一个 警告说foo.hpp

  2. 包含Foo的任何代码都可以看到bar()的声明。我不希望这样,因为可以通过在其他编译单元中重新定义bar()来使用它来访问Foo的私有成员。

  3. 所以这不起作用。你会如何解决这个问题?

    注意:当然sort_values实际上有一些参数用于访问In [135]: df['rank'] = df.sort_values(['col_a', 'col_b'])['col_b'].index + 1 In [136]: df Out[136]: col_a col_b rank 0 0 5 2 1 0 2 1 2 0 8 3 3 1 3 4 4 1 7 6 5 1 4 5 的特定实例。我在这里省略了它们。

3 个答案:

答案 0 :(得分:3)

只需使bar成为该类的静态成员函数。它使它成为一个全局函数,其名称作用于类(意味着您可以将其用作常规函数指针)。您甚至可以将其设为私有,因此只有您班级的成员可以调用它。

答案 1 :(得分:1)

这应该是你要找的东西:

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

如果您尝试调用Foo.cpp之外的modifyFoo(),则不会声明也不会定义它,因为它是private static friend Foo。如果您希望它对世界其他地方可见,那么您可以在课程中将其设为public。如果您正在使用继承和多态,那么您可以为所有子类创建protected,同时保持它不受外部对象的影响。

编辑 - 根据OP想要的性质,我必须这样做:它涉及使用包含静态方法的内部公共结构。然后该类具有调用修饰符的调用方法,但它也将返回内部结构。此结构是其父类的朋友。

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

输出

5
20
80

通过这种设置,您可以创建Foo::Modifier的实例,因为它在Foo的类中是公开的。它的内部方法是静态的,并引用Foo的特定对象,它是Foo的朋友。这样,您现在可以将Foo::Modifier的对象m作为struct传递到您的库,或者您可以使用m.modify( "some relative object of Foo" );传递函数地址

您要求的严格要求并非易事。

答案 2 :(得分:0)

我想要的似乎不可能。似乎唯一的选择如下:

  1. 不要将bar()中的函数foo.hpp声明为朋友,只在foo.cpp声明并将其定义为静态,并使用带有指针和强制转换的脏技巧来更改私有元素Foo的实例。我不喜欢这个。
  2. 删除bar()对于包含foo.hpp的代码不应显示的要求,并使用NathanOliver的答案。
  3. 删除bar()可以访问Foo实例的私有成员的要求,并在foo.cpp中使用匿名命名空间,我们在subFoo中派生Foo bar() (不添加新成员)并将foo.hpp定义为匿名命名空间中的友元函数,并且不在标题Foo中声明它。如果我们在Foo中将subFoo的实例投射到bar(),它就可以访问至少受保护的fputs(strstr(line, p_name), fp2); 成员。
  4. 我将使用第三个选项。