草庐IT

c++ - 内部类、pimpl 和一个 friend 类——不同意的编译器

coder 2024-02-05 原文

我正在研究一些旧的库代码,其基本目标是重构它。这段旧代码并不完全符合最佳实践和美观(是的 - friend 是坏人,在发现以下内容后已将其删除 - 因为它是重构中的疏忽)。

现在准备运行一些单元测试,我用 clang++、g++ 和 vc++ 编译了代码(2005 - 是的,我知道它很旧,但为了向后兼容 - 我必须这样做)。

g++ 和 clang++ 编译和运行没有错误,但是 Visual C++ 报错,所以在查看代码后,我发现了一些类似的东西:

#include <iostream>

class one {

  private:
    struct private_impl;
    private_impl* pimpl_;

  public:
    one();
    ~one();
    void say_hello();
};

class two {

  private:
    friend class one;
    void say_world();

  public:

};

struct one::private_impl {
  two t;
  void say_world();
};

void one::private_impl::say_world() {
   std::cout << " ";
   t.say_world();  //This should not work should it?
}

one::one() : pimpl_(new private_impl) { }

one::~one() {
  delete pimpl_;
}

void one::say_hello() {
  std::cout << "Hello";
  pimpl_->say_world();
  std::cout << std::endl;
}

void two::say_world() {
  std::cout << "World";
}

int main() {
  one test;
  test.say_hello();
  return 0;
}

使用开关编译(g++ 和 clang++):

-Wall -Wextra -pedantic

clang++ version: 3.3
g++ version:     4.8.2

现在 Visual C++ 提示 private_impl::say_world() 无法访问类二的私有(private)成员。在查看了 c++ friend 规则后,对我来说,这是正确的——但我对此的理解是错误的吗?我是否误读了信息(英语不是我的母语)?

根据标准(c++03 - 我现在手头没有 c++11):

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (clause 11) shall be obeyed.

还有这个:

Friendship is neither inherited nor transitive.

所以我的基本问题 - 谁才是真正正确的 - clang 和 gcc 或 vc++?

此外 - 这个问题只是出于对此事的好奇,并试图更好地了解这个世界。

最佳答案

周围类成员的可访问性受CWG 45影响。 .这意味着,至少部分问题已被归类为 C++98 标准中的缺陷。 (好像在2001年就提出了解决方案,所以我不太明白为什么在C++03中还没有修复。)

在C++11中,合并了解析,所以段落改为[class.access.nest]/1:

A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed. [Example:

class E {
    int x;
    class B { };

    class I {
        B b;                     // OK: E::I can access E::B
        int y;
        void f(E* p, int i) {
            p->x = i;            // OK: E::I can access E::x
        }
    };

    int g(I* p) {
        return p->y;             // error: I::y is private
    }
};

end example]

(一些)建议的缺陷解决方案在编译器中实现;注意g++ for example specifically says -std=c++03 标志表示

The 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports.

所以使用这个标志时你得到的结果并不明显。然而,DR 是“委员会意图的指示”,因此它们可以被视为标准中的“错误”,应该被修复。


VC++2005 似乎没有按照原始标准执行建议的解决方案。

关于c++ - 内部类、pimpl 和一个 friend 类——不同意的编译器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21134306/

有关c++ - 内部类、pimpl 和一个 friend 类——不同意的编译器的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  6. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. ruby - 是否可以从也在该模块中的类内部调用模块函数 - 2

    在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC

  9. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

  10. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

随机推荐