Devaniti
Devaniti

Reputation: 86

Accessing private struct of a class using auto

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

Answers (4)

Asteroids With Wings
Asteroids With Wings

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

Emmef
Emmef

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

dfrib
dfrib

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

Related Questions