30 votes

Pourquoi les méthodes de struct ne doivent-elles pas être déclarées en C ++?

Prenez, par exemple, le code suivant:

#include <iostream>
#include <string>

int main()
{
    print("Hello!");
}

void print(std::string s) {
    std::cout << s << std::endl;
}

Lorsque vous essayez de construire cela, je reçois le texte suivant:

program.cpp: In function ‘int main()':
program.cpp:6:16: error: ‘print' was not declared in this scope

Ce qui est logique.

Alors, pourquoi puis-je effectuer un concept similaire dans une structure, mais pas de faire hurler dessus pour qu'il?

struct Snake {
    ...

    Snake() {
        ...
        addBlock(Block(...));
    }

    void addBlock(Block block) {
        ...
    }

    void update() {
        ...
    }

} snake1;

Non seulement ai-je pas obtenir des avertissements, mais le programme compile! Sans erreur! Est-ce juste la nature de leurs structures? Ce qui se passe ici? Clairement addBlock(Block) a été appelé avant que la méthode n'a jamais été déclaré.

15voto

NirMH Points 2240

Un struct en C ++ est en fait une définition class où son contenu est public , sauf indication contraire en incluant une section protected: ou private :.

Lorsque le compilateur voit un class ou struct , il digère d'abord toutes les déclarations dans le bloc ( {} ) avant d'opérer dessus.

Dans le cas de la méthode régulière, le compilateur n'a pas encore vu le type déclaré.

13voto

v.oddou Points 1259

C++ standard 3.4.1:

.4:

Un nom utilisé dans la portée globale, en dehors de toute fonction, de classe ou de l'utilisateur déclaré espace de noms, doit être déclarée avant son utilisation dans le mondial la portée.

C'est pourquoi les variables globales et les fonctions ne peuvent pas être utilisés avant d'une même déclaration.

.5:

Un nom utilisé dans un utilisateur déclaré espace de noms en dehors de la définition de toute classe ou de fonction doit être déclarée avant son utilisation dans l' espace de noms ou avant son utilisation dans un espace de noms enfermant son espace de noms.

même chose juste écrit à nouveau que l'.4 paragraphe explictely restreint son disant "global", ce paragraphe dit maintenant "par la voie, de son vrai aussi dans namespeces les gens..."

.7:

Un nom utilisé dans la définition d'une classe X en dehors d'un membre corps de la fonction ou de la classe imbriquée definition29 doit être déclaré dans l'une des l'une des manières suivantes: - avant son utilisation dans la classe X ou être membre d'un de la classe de base de X (10.2), ou - si X est une classe imbriquée de la classe Y (9.7), avant la définition de X dans Y, ou est membre d'une classe de base de Y (cette recherche s'applique tour à tour, Y s 'enfermant les classes, à partir avec le plus profond classe englobante),30 ou - si X est une classe locale (9.8) ou est une classe imbriquée d'un local de classe, avant la définition de la classe de X dans un bloc englobant de la définition de la classe X, ou - si X est un membre de l'espace de noms de N, ou est une classe imbriquée d'une classe qui est un membre de la N, ou dans un local de classe ou d'une classe imbriquée à l'intérieur d'un local la classe d'une fonction qui est un membre de la N, avant la définition de la classe de X dans l'espace de noms N ou dans l'un de N, s 'enfermant les espaces de noms.

Je pense que ce qui parle de tout le code qui ne se tient pas dans la cpu de code exécuté (par exemple déclarative code).

et enfin la partie la plus intéressante:

3.3.7 portée de Classe [basic.scope.class]

1 Les règles suivantes décrivent la portée de noms déclarés dans les classes.

1) La portée potentielle d'un nom déclaré dans une classe se compose non seulement de la région déclarative à la suite du nom du point de déclaration, mais aussi à l'ensemble de la fonction corps, corset ou égal initialiseurs de non-membres de données statiques, et les arguments par défaut dans la classe (y compris dans les les classes).

2) Un nom N utilisé dans une classe S se réfèrent à la même déclaration dans son contexte et à la ré-évalué dans le la portée de S. Aucun diagnostic n'est requis pour une infraction à cette règle.

3) Si la réorganisation des déclarations de membre dans une classe donne une alternative valable programme en vertu de (1) et (2), le programme est mal formé, pas de diagnostic est nécessaire.

en particulier, par le dernier point qu'ils utilisent d'une manière négative à définir que "aucune commande n'est possible", parce que si la réorganisation des changerait de recherche puis il y a un problème. ses négative façon de dire "vous pouvez réorganiser tout et son ok, il ne marche pas changer quoi que ce soit".

effectivement en disant, dans une classe, la déclaration est recherchée dans les deux phases de la compilation de la mode.

5voto

Tony D Points 43962

"pourquoi puis-je effectuer un concept similaire dans une structure, mais pas de faire hurler dessus pour elle?"

En struct ou class définition vous êtes à la présentation de l'interface publique d'une classe, et il est beaucoup plus facile à comprendre, la recherche et le maintien/mise à jour de l'API si elle est présentée dans:

  • un ordre prévisible, avec
  • encombrement minimal.

Pour l'ordre prévisible, les gens ont leurs propres styles et il y a un peu de "l'art" impliqués, mais pour l'exemple, j'utilise chaque spécificateur d'accès au plus une fois, et toujours public avant protected avant private, puis à l'intérieur de ceux que j'ai l'habitude de mettre typedefs, const données, constructeurs, destructeurs, la mutation/non-const fonctions, const fonctions, statics, friends....

Pour réduire l'encombrement, si une fonction est définie dans la classe, il pourrait aussi bien être sans une déclaration préalable. Ayant à la fois le plus souvent à masquer l'interface.

Ceci est différent de fonctions qui ne sont pas membres d'une classe où les gens qui aiment de haut en bas de la programmation n'utiliser les déclarations de fonction et de masquer les définitions plus loin dans le fichier - en ce que:

  • les gens qui préfèrent une bottom-up style de programmation n'apprécie pas d'être forcé d'avoir des déclarations distinctes dans les classes ou abandonner la souvent contradictoires la pratique de regroupement par spécificateur d'accès

  • Les Classes sont statistiquement plus susceptibles d'avoir de nombreux très court fonctions, en grande partie parce qu'ils fournissent de l'encapsulation et d'emballer beaucoup de trivial membre de données d'accès ou de fournir la surcharge des opérateurs, opérateurs de casting, implicites constructeurs et d'autres fonctionnalités pratiques qui ne sont pas pertinentes pour le non-OO, non-membre de fonctions. Que fait une constante de la séparation forcée des déclarations et les définitions de plus en plus douloureux pour de nombreuses classes (pas tellement dans les interfaces publiques où des définitions peut-être dans un fichier séparé, mais certainement pour, par exemple, les classes anonymes espaces de noms à l'appui de l'actuelle unité de traduction).

  • La meilleure pratique est pour les classes de ne pas fourrer sauvagement dans une vaste interface... en général, vous voulez un noyau fonctionnel et puis certains discrétionnaire fonctions de confort, après quoi il est utile d'examiner ce qui peut être ajouté en tant que non-membre de fonctions. L' std::string est souvent accusé de trop nombreuses fonctions de membre, même si personnellement, je pense que c'est tout à fait raisonnable. Encore, ceci est différent aussi à partir d'un fichier d'en-tête de la déclaration d'une interface de la bibliothèque, où exhaustive fonctionnalité peut s'attendre à être entassés faire une séparation de même inline mise en œuvre plus souhaitable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X