使用未命名的名称空间在API中重新定义好友类并访问私人成员?

问题描述:

我试图访问一些类的私有成员,这些成员是我无法更改的API的一部分。使用未命名的名称空间在API中重新定义好友类并访问私人成员?

清单1:api.h

namespace api { 
    class Bar; 

    class Foo { 
    public: 
     const int& getSecret() const { return secretValue; } 
    private: 
     int secretValue; 
     friend class Bar; 
    }; 
} 

清单2:program.cpp

#include <iostream> 
#include "api.h" 

namespace { 
    class api::Bar { 
     public: 
      void touchFooSecretly(api::Foo& f) { f.secretValue = 42; } 
    }; 
} 

int main() 
{ 
    api::Foo f; 
    api::Bar b; 

    b.touchFooSecretly(f); 

    std::cout << f.getSecret() << std::endl; // 42 (Solaris) 
    return 0; 
} 

这将编译(和运行)在细的Oracle Solaris工作室12.3,但铛和g ++(可以理解)有问题:

program.cpp:5:13: error: cannot define or redeclare 'Bar' here because namespace '' does not enclose namespace 'api' 

为了提高工作效率,现在正在使用这种黑客技巧,并且对班级内部运作有很好的了解。是否有办法在clang中实现类似的技巧,以便我可以单独更改我的翻译单元的朋友类的含义?

或者,如果失败了,任何可以让我在无法修改声明的类中访问私有成员的技巧将不胜感激!

+2

所以你想在整个程序中有多个不同的'Bar'定义?如果是这样,即使你成功编译它,行为也将是未定义的。 – 2014-11-08 08:38:07

+0

我的翻译单位将有我对Bar的定义,其余应用程序将不受影响(因为它已被编译和链接)。我认为这是明确的,但也许我错了。 – Dragos 2014-11-08 08:42:54

+1

另一个窍门是在'#include“api.h”'和'#undef private'之前添加'#define private public'。这太可怕了,但是然后secretValue将会公开...并且这很可能会与任何编译器一起编译;-) – jpo38 2014-11-08 12:25:13

正如在问题的文章中评论的,我不知道如何解决这个命名空间问题。但是,正如笔者,any trick that lets me access a private member in a class where I cannot modify the declarations would be appreciated!要求......这是我的绝招:

#define private public 
#include "api.h" 
#undef private 

这是可怕的,但如果你知道你在做什么,这会让所有的私有成员在“api.h的类中声明“(+其他所有可能在文件中声明的类包含”api.h“)被公开!