【问题标题】:Global namespace friend class cannot access private member of named namespace class全局命名空间友元类不能访问命名命名空间类的私有成员
【发布时间】:2021-01-02 03:12:37
【问题描述】:

在命名空间类中,我将一个类(在全局命名空间中)声明为友元。 但是,后一个类不能访问前一个类的私有成员。为什么是这样?有什么办法吗?

鲍勃.h

namespace ABC {
    class Bob {
        friend class Joe;
        public:
            Bob ();
            int pub_number;
        private:
            int priv_number;
    };
}

Bob.cc

#include "Bob.h"

ABC::Bob::Bob () {
    pub_number=10;
    priv_number=6;
}

Joe.h

class Joe {
    Joe ( );
};

Joe.cc

#include "Joe.h"
#include <iostream>
#include "Bob.h"

Joe::Joe ( ) {
    ABC::Bob b;
    std::cout << b.pub_number << std::endl;
    std::cout << b.priv_number << std::endl;
}

以上代码在编译时产生如下错误:

Joe.cc:8:16: error: ‘int ABC::Bob::priv_number’ is private within this context
INFO: 1>     8 | std::cout << b.priv_number << std::endl;

如果我执行与上面相同的代码,但没有任何“Bob”类的命名空间,那么代码就会编译。

我尝试在 Bob.h 中转发声明 Joe 类,如下所示:

class Joe; // This does nothing to help

class ::Joe // This produces compiler message "error: ‘Joe’ in namespace ‘::’ does not name a type"

【问题讨论】:

  • 你把Joe的前向声明放在Bob.h的什么地方?如果它在 namespace ABC 内部,它不会声明与全局命名空间中相同的类。
  • 我试着把它放在不同的地方。我在命名空间外、命名空间内和类内尝试过。都给出了相同的结果。

标签: c++ class namespaces friend name-lookup


【解决方案1】:

您需要在全局命名空间中添加一个无范围的前向声明,并在声明朋友时使用范围运算符:

class Joe;  // Forward declaration

namespace ABC {
    class Bob {
        friend class ::Joe;  // Use the Joe class from the global scope
        public:
            Bob ();
            int pub_number;
        private:
            int priv_number;
    };
}

【讨论】:

  • 我看到了一些朋友声明在“私人”中的代码,有什么理由把它放在那里吗?
  • @didjek friend 声明独立于访问说明符,例如 public 或 private。他们的位置取决于个人喜好。
【解决方案2】:

您的friend 声明也需要:: 前缀:

class Joe;

namespace ABC {
    class Bob {
        friend class ::Joe;
        //           ^^ here

        ...
     };
 }

【讨论】:

  • 嗨,和上一张海报一样。这就是我一直在寻找的答案。
【解决方案3】:

在这个类定义中

namespace ABC {
    class Bob {
        friend class Joe;
        public:
            Bob ();
            int pub_number;
        private:
            int priv_number;
    };
}

朋友类Joe的声明在命名空间ABC的范围内引入了名称Joe,因为类Joe的先前声明是不可见的并且使用了非限定名称。

来自 C++ 标准(10.3.1.2 命名空间成员定义)

  1. ... 如果朋友声明中的名称既不是限定的也不是 模板 ID 和声明是一个函数或一个 详细类型说明符,查找以确定实体是否 已事先声明不得考虑任何范围之外的 最里面的封闭命名空间。

您需要在类Bob 的声明之前将Joe 类的声明放在全局命名空间中,并且在Bob 类中您必须使用朋友类的限定名称,至少像

class Joe;

namespace ABC {
    class Bob {
        friend class ::Joe;
        public:
            Bob ();
            int pub_number;
        private:
            int priv_number;
    };
}

或者您可以在命名空间 ABC 中使用 using 声明,例如

class Joe;

namespace ABC {
    using ::Joe;

    class Bob {
        friend class Joe;
        public:
            Bob ();
            int pub_number;
        private:
            int priv_number;
    };
}

【讨论】:

    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 2012-08-06
    • 2011-01-15
    相关资源
    最近更新 更多