I was mucking about in some old library code, with the basic objective of refactoring it. This old code does not exactly comply to best practices and beauty (yes - friends are bad, and it has been removed after discovering the below - as it was an oversight in the refactoring).
Now preparing to run some unit tests I compiled the code with clang++, g++, and vc++ (2005 - yes I know it's old, but for backward compatibility - I have to).
g++ and clang++ compiled and ran without errors, but Visual C++ was complaining, so after looking at the code, i found something to the effect of this:
#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;
}
Compiled with switches (g++ and clang++):
-Wall -Wextra -pedantic
clang++ version: 3.3
g++ version: 4.8.2
Now Visual C++ complains that private_impl::say_world() cannot access the private member of the class two. To me after looking over the c++ friend rules, this is correct - but is my understanding of this wrong? Am I misreading the information (English is not my first language)?
From the standard (c++03 - do not have c++11 at hand where I'm at now):
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.
And also this:
Friendship is neither inherited nor transitive.
So my basic question here - who is actually correct - clang and gcc or vc++?
Also - this question is just for curiosity about the matter, and trying to understand the world a little better.
// OK: E::I can access E::B
– Perrine