为什么这段代码可以编译通过?

5

如何决定其他对象私有部分嵌套的对象的访问权限?

例如,在下面的代码片段中,proxy_t结构体被嵌套在abc_t的私有部分中,但其方法仍然可以在main函数中使用。为什么这个代码可以编译通过?

#include <iostream>
#include <valarray>

using namespace std;

class abc_t{
  private: 
    struct proxy_t{
      proxy_t operator()(double& a, double& b){ __a=a; __b=b; return *this; }
      double a(){ return __a; }
      double b(){ return __b; }
      private:
        double __a, __b;
    };

  public:
    abc_t( const size_t N ){ 
       _a.resize(N,-101.); 
       _b.resize(N,-202.);  
    }
    double a(size_t j){ return _a[j]; }
    double b(size_t j){ return _b[j]; }

    proxy_t operator[](const size_t j) { return _proxy(_a[j],_b[j]); }

  private:
    valarray<double> _a;
    valarray<double> _b;
    proxy_t _proxy;
};


int main(){
 size_t n_elem=10;
 abc_t abc(n_elem);
 cout<<"direct: "<< abc.a(1)<<"  "<<abc.b(1)<<"\n";
 cout<<"proxied:"<<abc[1].a()<<"  "<<abc[1].b()<<"\n";  // ain't proxy_t::aa() private?
 //cout<<abc[1]; // doomed to fail
}

1
gnu,intel,pgi,Visual Studio Express 2010 C++ - ev-br
2
不知道,但是双下划线的使用是非法的。 - user2100815
4个回答

5

这一行是我要讨论的重点:

cout<<"proxied:"<<abc[1].a()<<"  "<<abc[1].b()<<"\n";

当你调用abc[1]时,这是abc_t的一个公共方法。这是有效的。

它返回一个proxy_t。虽然这个类(proxy_t)的声明没有被定义,但你实际上并没有使用返回变量来创建一个新对象。如果你按照以下方式做,它将无法编译。

proxy_t p = abc[1];

因为声明了proxy_t,你正在初始化一个新对象,但是该类型在该范围内不存在。由于您实际上没有声明该类型的任何变量,在该范围内也没有创建任何proxy_t(这将是非法的)。
通过将proxy_t设置为私有,这仅意味着除了abc_t类内部之外,您无法在任何地方创建该类型的任何对象。但是,它作为返回值被传递是有效的--没有创建/实例化/声明任何对象,只是使用现有的对象。
然后是有趣的部分。使用类时,默认情况下所有内容都是私有的(除非另有规定)。对于结构体,默认情况下所有内容都是公共的。因此,proxy_t :: a()是公共的,因此可以在main函数中使用,因为main函数恰好可以访问proxy_t对象。

3
如果你这样说,它会崩溃。你的意思应该是这段代码无法编译通过。 - Neowizard
@arasmussen:让我感到困惑的是:天真地说,我希望abc[1].a()等同于在main()函数中使用_proxy.a()方法,而后者显然是非法的。 - ev-br
@Zhenya:由于abc [1]返回一个proxy_t,而您没有实例化任何类型的proxy_t,因此它是合法的。您只是不能在该范围内实例化任何类型为“proxy_t”的东西。在您的情况下,您并没有这样做,您只是在调用其他地方存在的对象上的公共方法。 - Andrew Rasmussen
@arasmussen:你是在说这个 abc_t 的其他地方是私有区域并不重要吗? - ev-br
2
@Zhenya - 这就像是一个函数返回了类的私有数据的引用。只有在类允许你访问它之后,你才能使用它,但是不能自己获取访问权限。 - Bo Persson

1

你将结构体proxy_t定义为私有的,但它实际上公开了方法。我猜测你的编译器不允许你在主函数中直接实例化一个proxy_t结构体,但如果你从abc_t类返回一个proxy_t结构体,它将允许你调用公共方法。

也许了解C++标准的人可以评论一下这是否是编译器的正确行为。


0

你在说 abc[1].a(),它的意思是去这里:

proxy_t operator[](const size_t j) { return _proxy(_a[j],_b[j]); }

这是公共的,并将1作为j的参数抛出。然后它返回

_proxy(_a[j],_b[j]) 

这是调用您用于访问a()函数的私有结构体


0

由于proxy_tabc_t的私有成员,除了abc_t之外,没有人可以使用它(即无法实例化此类型的对象)。但是,对于现有的proxy_t,每个人都可以调用其成员-因为它们是公共的。

标准在这里有点枯燥(或者我看错了地方),但这是我找到的最好的结果(11.8):

嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。封闭类的成员没有特殊访问嵌套类成员的权限;应遵守通常的访问规则(第11条)。

读懂其中含义:由于嵌套类“只是”一个成员,因此当某人引用此类型(即拼写出proxy_t)时,将应用通常的访问控制。但是对于访问proxy_t本身的成员,不适用特殊的访问规则-如果您成功从特权源获取了proxy_t对象,则可以像访问非嵌套类一样访问其成员。


让我感到困惑的是:天真地说,我认为abc[1].a()等同于在main()函数中使用_proxy.a()方法,而后者显然是不合法的。此外,如果proxy_t只是abc_t的成员之一,那么它是一个私有成员。为什么它的成员会暴露出来? - ev-br

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