【问题标题】:Instance of private nested class c++ [duplicate]私有嵌套类c ++的实例[重复]
【发布时间】:2015-02-18 19:39:46
【问题描述】:

我有以下代码

class A
{
private:
    class B
    {
    public:
        void f()
        {
            printf("Test");
        }
    };
public:
    B g() 
    {
        return B(); 
    }
};


int main()
{
    A a;
    A::B b; // Compilation error C2248
    A::B b1 = a.g(); //Compilation error C2248
    auto b2 = a.g(); // OK
    a.g(); // OK 
    b2.f(); // OK. Output is "Test"
}

如您所见,我有 A 类和私有嵌套 B 类。 如果不使用 auto 我无法在 A 之外创建 A::B 的实例,但使用 auto 我可以。 有人可以解释这里有什么问题吗? 我使用 VC++ 12.0、13.0、14.0(总是相同的行为)

【问题讨论】:

  • 当然,您无权访问类范围之外的私有成员。这就是他们的目的。
  • 如果我没记错的话,访问控制实际上适用于names。当使用auto 时,类型不是命名的,而是推导的,因此可以访问。我对么?见stackoverflow.com/q/21736828/10077
  • 顺便说一句,我使用 g++ 4.8.1 使用此代码得到了相同的结果。不仅仅是 MSVC++。
  • @milleniumbug:确实,我认为这个问题是重复的。

标签: c++ visual-c++ c++11


【解决方案1】:

B类型只有AA的朋友可以访问,也就是说其他代码不能引用它。另一方面,模板类型推导甚至适用于私有类型,如果您想在A 的代码中的任何形式的模板中使用您的私有类型,则需要这样做。

auto功能基于模板类型推导,遵循相同规则,允许调用auto b2 = a.g();

【讨论】:

  • 问题是,然而“模板类型推导对私有类型也有效”,但是为什么推导的类型不会出错呢?
  • @MM。假设您有template <typename T> void foo(T const &);。您希望能够使用您的类私有类型的实例调用foo()。如果我正确理解这一点,该语言会例外,并说模板类型参数(例如 T 可以)如果推导出来引用私有类型,即使 foo() 模板本身没有'无权访问该名称。 auto 遵循相同的规则。
  • @MM:考虑到A::some_member 想做一些简单的事情:auto x = std::make_shared<B>(); 这需要工作。在make_sharedshared_ptr 中,B 类型不可访问,但如果私有成员类型有用,则此代码需要工作。如果类型是从可以访问该类型的代码传递过来的,那么模板需要能够处理它们无法直接访问的类型。 -- cdhowie:类型不需要推导,只要提供类型的人有访问权限,就可以指定(如上make_shared<B>)。
  • ... 另请注意,问题中的代码本身是 strange 的。类型是 private,但是有一个公共函数返回它,这使得类型同时 privatepublic 的一部分界面。如果公共接口中没有函数产生B 对象,则没有外部代码能够访问它。 A 给你B 对象,auto 只是允许调用者代码编译。这与产生指向内部私有成员的成员指针的公共函数并无太大不同。
  • 我称之为 C++ 标准中的不一致。 auto 关键字应该可以被实际类型替换(lambda 函数除外)。让私人访问不应该是一个技巧!它会导致坏习惯。
【解决方案2】:

类型扣除!

当您将私有类 (A::B) 嵌入到另一个类中时,只有外部类能够创建私有类型 A::B 的对象。

以下声明试图创建一个您无权访问 A::B 的对象:

A::B b; // Compilation error C2248
A::B b1 = a.g(); //Compilation error C2248

这是因为在main() 函数中,您无法“看到”(或访问)隐藏在A 中的私有类。 auto 解决了这个问题。公共函数A::g() 能够创建A::B 的实例,并将其返回给您。

auto 通过稍后推断类型来解决这个问题。当编译器处理推断auto b2 = a.g();的类型时,会发现类型是A::B。这没关系,因为A::g()A 的成员函数,并且可以访问A::B

本质上,只有A 的成员才能声明A::B,但A::B 可以通过A 的公共成员推导出来,该成员返回A::B

【讨论】:

  • decltype(a.g()) instance_of_b; 允许在 a 在范围内的任何地方实例化 B
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 2017-02-10
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多