声明命名空间为类的友元

31

我想知道是否有一种方法可以在特定命名空间中定义的所有函数都与类成为朋友?

具体而言,我有一个类,例如:

class C {
    private:
        // ...
    public:
        // ...

        friend C* B::f1(C*);
        friend C* B::f2(C*);
        friend C* B::f3(C*);
        friend C* B::f4(C*);
        friend C* B::f5(C*);
};

并且有一个名为 B 的命名空间:

namespace B {
    C* f1(C* x);
    C* f2(C* x);
    C* f3(C* x);
    C* f4(C* x);
    C* f5(C* x);
};

现在,我更希望避免在类定义中写入5行代码,以使命名空间B的所有五个函数都成为类C的友元,并告诉编译器在命名空间B内定义的所有函数都是类C的友元(即可以访问其私有成员)。

我猜一个快速的解决方法是将命名空间改为一个类,并将函数定义为其静态成员,然后声明类B为类C的友元。但是,出于好奇,我想知道是否也可以对命名空间进行这样的操作?

谢谢提前。

2个回答

29
不,无法和命名空间成为好友。否则,这将构成“安全漏洞”,因为命名空间可以在任何地方扩展。所以任何人都可以向命名空间添加任意函数并访问类的非公开数据。
最接近的解决方法是您提出的解决方案,即使那些函数成为类的静态成员并成为类的朋友。但反过来想,为什么不首先将它们作为原始类(代码中的)的静态成员呢?
此外,如果我在我的代码中遇到了需要如此多的友元函数的情况,我会认真考虑我的设计是否有问题;我会把它看作一个信号,让我重新思考我的设计。

10
这样做的一个好理由是为了测试。有时,如果能够访问私有成员变量,编写测试会更容易。一些人认为这很糟糕,因为它违反了“黑盒”测试原则,但实际上,在某些情况下进行“白盒”测试会更好。 - Timmmm
6
"这将构成一次‘安全漏洞’" - 在这种情况下,攻击者是谁?开发人员吗?您正在针对程序员采取防御措施,这些程序员被认为是天生愚蠢的吗?" - Tom
3
请注意引号。然而,如果您认为私有数据不需要保护,免受类设计者未预期的修改,那么为什么不一开始就强制所有内容为公共的,并完全摒弃“private”和“protected”呢? - Angew is no longer proud of SO
1
@Angew - "为什么不一开始就强制将所有内容公开,然后彻底摆脱私有和受保护的属性?"实际上,我认为这正是我们应该做的。最好使用一些命名约定来指示成员不应由外部类修改,并且你已经成功地删除了 25%+ 的 getter/setter 样板代码。面向对象编程架构的迷恋只会削弱整洁的数据导向设计,而且还会使代码更加复杂(通常速度也更慢)。 - Tom
2
@Tomis,我的意思是Python。但是我更喜欢C++的编译时安全性,而不是Python的“让我们假设我们都知道彼此的意图”。我认为我们应该就这个问题达成不同意见的共识。 - Angew is no longer proud of SO
显示剩余2条评论

6
如果您将您的命名空间提升为一个类,那么您可以一次性添加很多函数为友元。 虽然这样做会带来(许多)其他缺点,但您可能确实希望有一个B类(出于其他原因)。
class C {
    private:
        // ...
    public:
        // ...

    friend struct B_domain;
};

struct B_domain {
    static C* f1(C* x);
    static C* f2(C* x);
    static C* f3(C* x);
    static C* f4(C* x);
    static C* f5(C* x);
};

除了被迫写C::(这可能被视为一种特性)之外,还有什么其他许多缺点? - Beyondo
@Beyondo,没有ADL,这可以被视为一种特性。对于操作员来说也是无用的。如果您不喜欢冗长的话,它也太啰嗦了。 - alfC
@Beyondo 这也是冗长的,因为你需要在各处使用 static。它还需要更多的样板文件,因为类可以被实例化。 - alfC

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