J'ai découvert que le prochain code étrange se compile et s'exécute (sur 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;
}

La sortie est de 42, aucun problème ici.

Le problème que je vois est que le mot-clé auto nous permet d'accéder à la structure privée "Priv". Si j'essaye de remplacer auto par Test :: Priv, j'obtiens une erreur de compilation, comme prévu. D'après les articles sur Internet, j'ai découvert que vous pouvez avoir à utiliser auto pour les lambdas, mais ce cas n'a jamais été mentionné.

Aussi, si j'essaye de sortir "Test :: WeirdFunc (). A" ça marche aussi

Mes questions sont donc:

  • Est-ce un comportement attendu pour auto pour nous permettre d'accéder à des structures / classes privées?
  • Est-il autorisé à déclarer une fonction publique qui renvoie une structure privée?
  • Est-ce un comportement attendu que nous pouvons accéder aux structures / classes privées si c'est la valeur de retour de la fonction (par exemple "Test :: WeirdFunc (). A")?

Tout cela est évidemment un style de code terrible, mais je suis curieux de savoir si c'est du code C ++ valide ou non

4
bestdark 23 oct. 2020 à 13:34

4 réponses

Meilleure réponse

Le résultat de Test::WeirdFunc() est un Priv. C'est également le type de val à déduction automatique. Le mot clé auto supprime la nécessité de nommer le type de val pour être Priv et par conséquent, le compilateur ne se plaint pas. En conséquence, val est de type (non mentionné) Priv et a un membre public a, auquel il est possible d'accéder librement.

Donc la réponse à toutes vos questions est: Oui , (tant que vous ne "mentionnez" pas le nom de la classe imbriquée).

Voir aussi: référence cpp sur les classes imbriquées

4
Emmef 23 oct. 2020 à 12:18

Mes questions sont donc:

  • Est-ce un comportement attendu pour auto pour nous permettre d'accéder à des structures / classes privées?

Oui.

  • Est-il autorisé à déclarer une fonction publique qui renvoie une structure privée?

Oui.

  • Est-il prévu que nous puissions accéder à des structures / classes privées si c'est la valeur de retour de la fonction (par exemple Test::WeirdFunc().a)?

Oui.

Tout cela est évidemment un style de code terrible, ...

Non pas forcément. Pensez par exemple à une classe de conteneur, qui définit les classes d'itérateur comme des types imbriqués internes:

class Container {
     class iterator {
     public:
          iterator operator++(); 
          iterator operator++(int); 
     };

public:
     iterator begin();
     iterator end();
};

Cela permet d'accéder aux instances et opérations de iterator via auto, mais pas de créer directement des instances depuis l'extérieur de la classe.

3
πάντα ῥεῖ 23 oct. 2020 à 11:08

C'est valide, et voici pourquoi:

Les spécificateurs d'accès contrôlent l'accès aux noms .

Donc, vous n'avez pas accès au nom Priv, mais cela ne signifie pas que vous n'avez pas accès au type auquel il fait référence. Et il existe d'autres moyens pour "y accéder", par exemple en utilisant auto.

Ce n'est pas aussi fou qu'on pourrait le penser. Après tout, vous ne pouvez pas faire de dégâts avec cela: si vous ne voulez pas que les choses publiques retournent des instances de "types privés" (ce qui ne le sont pas vraiment, mais c'est bien) alors ne faites tout simplement pas cela.

0
Asteroids With Wings 23 oct. 2020 à 23:27

Vous disposez d'une interface publique qui expose un type au moyen du type de valeur de retour de l'interface publique. Cela signifie essentiellement que la conception de votre API expose des détails privés de la classe, et ce n'est pas un problème des fonctionnalités du langage C ++ mais de la conception de l'API. Notez que cela ne s'applique pas uniquement à auto:

using A = decltype(Test::WeirdFunc());  // A is Test::Priv.
A a{};  // well-formed.
2
dfrib 23 oct. 2020 à 10:46