C++ - Quel est l'intérêt des classes imbriquées?

j'étudie un peu le C++ et maintenant je me bats contre ses similitudes avec Java. Je connais le but des classes internes en Java, mais maintenant j'essaie d'utiliser des classes imbriquées en C++, et je découvre que les attributs privés de la classe "container" ne sont pas visibiles par classe imbriquée , alors pourquoi devrais-je les utiliser? Aussi, est-il un moyen de rendre visible ces attributs?

29
demandé sur Leo91 2015-07-09 10:09:19

3 réponses

j'étudie un peu le C++ et maintenant je me bats contre ses similitudes avec Java.

tout d'abord, sachez que les classes imbriquées C++ sont similaires à ce que vous appelez en Java classes imbriquées statiques . Il n'y a rien dans la syntaxe C++ pour reproduire Java classes imbriquées .

je découvre que privé les attributs de la classe" conteneur " ne sont pas visibles par classe intérieure...

C++ 98

en C++ Les classes internes ne sont pas différentes des classes normales , elles ne sont pas de classe membres alors ils ne peuvent pas accéder aux membres privés de la classe container (contrairement à D'autres langues comme Java ou C#).

C++ 03

les classes imbriquées sont des membres de classe mais des restrictions sur ce qu'ils peuvent accéder s'applique toujours (voir aussi la section choses bizarres à la fin de cette réponse). Il a été considéré comme un défaut standard (voir DR45 ), puis certains compilateurs ont mis en place plus tôt la règle D'accès C++0x, même lors de la compilation pour C++03 (notamment GCC, merci à Jonathan Wakely pour le repérer).

C++ 11

cette règle a changé en C++ 11, Les classes maintenant imbriquées peuvent accéder à private member de la classe container. Paragraphe 11.7:

une classe imbriquée est un membre et, à ce titre, a les mêmes droits d'accès que tout autre membre.

bien sûr, vous avez encore besoin d'une instance pour accéder aux membres non statiques.


...alors pourquoi je devrais utiliser?

Ils sont alors un mise en œuvre détail de groupe classes connexes et ils ont les mêmes questions sur leur utilisation que vous pouvez avoir dans d'autres langues (clarté pour les débutants, primaire). Leur plus grand avantage IMO est encapsulation, si par exemple vous avez ceci:

class stream {
    virtual void write(const std::string text) = 0;
};

class channel {
public:
    virtual stream* get_stream() = 0;

    // Other methods...
};

class tcp_channel : public channel {
public:
    virtual stream* get_stream() {
        return new tcp_stream(this);
    }

private:
    class tcp_stream : public stream { /* implementation */ };
};

ils sont également utiles dans certaines circonstances à remplacer espaces de noms emboîtés:

class protocol {
public:
    virtual void create_connection() = 0;

    class tcp : public protocol { /* implementation */ };
    class shared_memory : public protocol { /* implementation */ };
    class named_pipes: public protocol { /* implementation */ };
};

auto media = protocol::tcp();

Ou de masquer les détails de mise en œuvre:

class file_system_entry {
public:
    class file : public file_system_entry { };
    class directory : public file_system_entry { };

    std::time_t get_last_modified() { ... }

    void remove() { ... }
    virtual void copy_to(std::string path) = 0;

private:
    class local_handle {
        // Implementation details
    } _handle;
};

il y a beaucoup d'autres modèles d'utilisation (voir aussi pourquoi utiliserait-on des classes imbriquées en C++? pour une bien meilleure discussion), juste se rappeler pas tout le monde sera correctement comprendre (et utiliser!) ils. Voir aussi avantages et inconvénients de l'utilisation de classes C++ imbriquées et énumérations?

aussi, y a-t-il un moyen de rendre visibles ces attributs?

avant C++ 11 Vous ne pouvez pas (bien sûr sauf si vous les déclarez comme friend s mais voyez le paragraphe suivant), si vous avez besoin de cette fonctionnalité, utilisez simplement un compilateur C++ 11 (qui supporte cette fonctionnalité). GCC le fait (depuis longtemps) et aussi MSVC le fait, je ne sais pas pour les autres compilateurs.

Imbriqués Amis

y a-t-il une différence entre les règles d'accès C++ 11 et les classes d'amis? en général ils sont presque équivalent ( automatique l'accès est juste moins verbeux):

class container {
public:
    class nested;
    friend class nested;

    class nested { };
};

par rapport à:

class container {
public:
    class nested { };
};

cependant avec la déclaration forward vous avez quelque effets secondaires . Rappelez-vous également que du point de vue de l'accessibilité, ils sont équivalents (l'accès, comme l'amitié, n'est pas hérité ni transitif). Ces exemples ne compilent pas:

class external : public container::nested {
public:
    // No: only class declared inside "container"
    // has access to private members, we do not inherit that 
    void foo(container obj) { /* access a private member of obj*/ }
};

// No, "container" has not access to "nested" private members,
// visibility isn't reciprocal
void container::foo(container::nested obj) {
    // Access some private member of obj
}

// No, we don't have anything to do with container,
// visibility isn't transitive
void friendOfNested(container obj) {
    // Access some private member of obj
}

sont alors tout à fait équivalent ? Non , parce que les membres privés des amis de container sont accessibles dans nested si c'est une classe imbriquée dans C++ 11 mais ils ne sont pas si nested est un ami de container . Compte tenu de cette structure esquissée:

class container;

class another {
    friend class container;     
};

class container {
public:
    class nested { };   
};

nested peuvent accéder à another 's les membres privés:

void container::nested::foo(another obj) {
    obj.somePrivateMember = 0;
}

ça marche parce que nested est un membre de container alors restriction transitive d'amitié ne s'applique pas. Avant C++ 11, déclarant nested comme ami de container , ce code ne sera pas compilé parce que l'amitié n'est pas transitive.

choses bizarres

nous supposons que nous pouvons toujours déclarer une classe emboîtée comme ami de son conteneur? En fait, la norme a dit (SO / IEC 14822: 2003(E), 11.8):

Un ami de classe est une fonction ou d'une classe qui n'est pas membre de la classe...

alors nous ne devrions pas être en mesure de déclarer nested comme ami de container : en C++ 03 classes imbriquées sont des membres de classe (mais standard explicitement dit qu'ils n'ont pas accès à des conteneurs privés et aussi ils ne peuvent pas être des amis de la classe de conteneur). Il semble qu'il n'y avait aucun espoir, heureusement la plupart des compilateurs nous ont permis de le faire (indépendamment ce standard a dit).

44
répondu Adriano Repetti 2017-05-23 11:46:14

il fournit une autre bonne technique d'encapsulation. Placer une classe entièrement dans l'Espace-nom d'une autre classe réduit sa visibilité à d'autres parties de votre base de code. Cela permet d'obtenir l'évolutivité et réduit votre fardeau de maintenance.

objets de fonction sont souvent codés de cette manière.

5
répondu Bathsheba 2015-07-09 07:14:17

Différent n'est pas le même.

Les classes

Java inner créent des objets qui sont supposés être connectés avec un objet de la classe outer , de sorte que l'accès aux membres de la classe externe à partir de méthodes de la classe interne peut être fait sans créer explicitement un pointeur ou une référence. C++ ne fait pas cela; une classe imbriquée est juste une classe dont la définition est imbriquée dans la définition d'une autre classe. classe. C'est pratique pour l'encapsulation, mais c'est tout: il n'est pas destiné à faire magiquement des objets de ce type connaître des objets du type contenant.

1
répondu Pete Becker 2015-07-09 13:09:36