为什么这段代码会编译?

时间:2011-04-27 16:54:02

标签: c++

确定嵌套到其他对象的私有部分中的对象的访问权限的确切规则是什么?

例如,在下面剪切的代码中,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
}

4 个答案:

答案 0 :(得分: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对象。

答案 1 :(得分:1)

您已将struct proxy_t定义为private,但它公开的实际方法是公共的。我的猜测是你的编译器不允许你直接在main中实例化一个proxy_t结构,但是如果从类abc_t返回一个结构,它将允许你在它上面调用公共方法。

也许知道C ++标准的人可以评论这是否是编译器的正确行为。

答案 2 :(得分:0)

你说的是abc [1] .a(),这里说:

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

是公开的并且为j投掷1。然后它返回

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

调用用于访问a()函数的私有结构

答案 3 :(得分:0)

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

这里的标准有点沉闷(或者我看错了地方),但这是我最好的发现(11.8):

  

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

在行之间阅读:由于嵌套类只是“成员”,因此当有人引用此类型时(即拼出proxy_t),将应用通常的访问控制。但是对于访问proxy_t本身的成员,没有特殊的访问规则适用 - 如果您设法从特权源获取proxy_t对象,您可以访问其成员,就像它不是嵌套类一样