I just happened to find that a nested private template class can be accessed directly outside the enclosing class using a using
directive:
class wrapper { private: template <typename T> class __tklass {}; class __klass {}; }; template <typename T> using tklass = wrapper::__tklass<T>; // Expected error but compiles OK // using klass = wrapper::__klass; // "Error: __klass is private" int main() { tklass<int> v1; // Expected error but compiles OK // wrapper::__tklass<int> v3; // "Error: __tklass is private" // wrapper::__klass v4; // "Error: __klass is private" }
The lines marked "Error: __xxx is private" correctly report an error when uncommented. But the lines with tklass
get compiled without any complaint from the compiler.
So why exactly doesn't the compiler flag tklass
as error despite wrapper::__tklass
being private? Is it by any chance allowed by the standard? If so, wouldn't that be considered a serious access violation?
I tried this on gcc-4.9.2, clang-3.5.0 and visual studio 2013 express. GCC command line:
g++ -std=c++11 -pedantic -Wall -Wextra -Wshadow myfile.cpp
Private: The class members declared as private can be accessed only by the functions inside the class. They are not allowed to be accessed directly by any object or function outside the class. Only the member functions or the friend functions are allowed to access the private data members of a class.
In C++, a friend function or friend class can also access private data members. So, is it possible to access private members outside a class without friend? Yes, it is possible using pointers.
Either make the function itself public or add another public function to call the private one: class cricket { private: // ... void cal_penalty_impl() { // Your original code goes here // ... } public: // ...
This is definitely a compiler bug, and actually one that has been known for quite some time: GCC #47346 (first reported in Jan 2011) and Clang #15914 (first reported May 2013). Your __tklass
is clearly private
, and the template alias is not marked friend
, so this should be a simple access error.
The simplest reproduction is from the Clang example attachment, this version compiles on both gcc 4.9.2 and clang 3.5.0, though should definitely compile on neither:
class A { class B {}; }; template<typename> using T = A::B; T<void> t;
Clang is strictly better than GCC on this front however, as this particular bug seems to occur only with template aliases. A "workaround" (if you need such a thing for cases that the compiler allows incorrectly...) would be to revert back to pre-C++11 template aliasing:
template <typename> struct T { using type = A::B; }; T<void>::type t;
That code correctly fails to compile with clang (error: 'B' is a private member of 'A'), but still compiles fine with gcc.
Herb Sutter wrote long ago the article, how template member functions may provide a back-door into a class: http://www.gotw.ca/gotw/076.htm (pls. check the case 4: "The Language Lawyer", at the end)
It may give you the answer.
EDIT: I'm curious, what were the reasons for down-voting. I cite the article: "Is this a hole in C++'s access control mechanism, and therefore a hole in C++'s encapsulation? This demonstrates an interesting interaction between two C++ features: The access control model, and the template model. It turns out that member templates appear to implicitly "break encapsulation" in the sense that they effectively provide a portable way to bypass the class access control mechanism."
Seems for me to be a reasonable answer. EDIT END
One could spent plenty of time trying to secure the interfaces by technical means private/protected, etc. My preferred way is to make an agreement among all developers to use well, understood rules complying with least surprise approach. (EDIT: And verify the code against these rules using the code-reviews/reg-exp scripts on regular basis)
"Don't try to find a technical solution for a social problem" B. Stroustrup
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With