Reputation: 86
I discovered that next weird code compiles and runs (on VS 2019):
#include <iostream>
class Test
{
private:
struct Priv
{
int a;
};
public:
static Priv WeirdFunc() {return {42};};
};
int main()
{
auto val = Test::WeirdFunc();
std::cout << val.a;
}
Output is 42, no problems here.
The issue I see is that auto keyword allows us to access private structure "Priv". If I try to replace auto with Test::Priv I get compile error, as expected. From the articles on the internet I found out that you can have to use auto for lambdas, but this case was never mentioned.
Also, if I try to output "Test::WeirdFunc().a" it also works
So my questions are:
All of that is obviously terrible code style, but I'm curious about whether it's valid c++ code or not
Upvotes: 6
Views: 585
Reputation: 17454
It's valid, and here's why:
Access specifiers control access to names.
So, you have no access to the name Priv
, but that doesn't mean you have no access to the type it's referring to. And there are other ways to "get to it", such as by using auto
.
This is not as crazy as you might think. After all, you can't do any damage with it: if you don't want public things returning instances of "private types" (which aren't, really, but that's fine) then simply don't do that thing.
Upvotes: 0
Reputation: 522
The result of Test::WeirdFunc()
is a Priv
. This is also the auto-deducted type of val
. The auto
keyword removes the necessity to name the type of val
to be Priv
and therefore, the compiler does not complain. As a result, val
is of (unmentioned) type Priv
and has a public member a
, that can be accessed freely.
So the answers to all your questions is: Yes, (as long as you don't "mention" the name of the nested class).
See also: cpp reference on nested classes
Upvotes: 5
Reputation: 1
So my questions are:
- Is it expected behaviour for auto to let us access private structures/classes?
Yes.
- Is it allowed to declare public function that returns private structure?
Yes.
- Is it expected behaviour that we can access private structures/classes if it's return value of function (e.g.
Test::WeirdFunc().a
)?
Yes.
All of that is obviously terrible code style, ...
No, not necessarily. Think about e.g. a container class, which defines iterator classes as internal nested types:
class Container {
class iterator {
public:
iterator operator++();
iterator operator++(int);
};
public:
iterator begin();
iterator end();
};
This allows to access the iterator
's instances and operations via auto
, but not to directly create instances from outside the class.
Upvotes: 3
Reputation: 73186
You have a public interface which exposes a type by means of the type of return value of the public interface. This essentially means your API design exposes private details of the class, and this is not an issue of the C++ language features but of the API design. Note that this doesn't just apply for auto
:
using A = decltype(Test::WeirdFunc()); // A is Test::Priv.
A a{}; // well-formed.
Upvotes: 2