2010-10-31 24 views
12

Si en C++ j'ai une classe longUnderstandableName. Pour cette classe, j'ai un fichier d'en-tête contenant sa déclaration de méthode. Dans le fichier source de la classe, je dois écrire longUnderstandableName::MethodA, longUnderstandableName::MethodB et ainsi de suite, partout. Puis-je utiliser des espaces de noms ou quelque chose d'autre de sorte que je peux simplement écrire MethodA et MethodB, dans le fichier source de classe, et seulement là?C++: "Class namespaces"?

+0

En ce moment, la réponse est non. ** Mais ** ... Il existe [une proposition visant à ajouter ** 'namespace class' ** à la langue] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/ 2016/p0223r0.html), ce qui permettrait d'obtenir exactement ce que vous, et moi, souhaitons: activer la définition de membres de classe déjà déclarés dans un bloc qui les étend automatiquement à la classe - et ainsi éviter le retypage constant de la portée du nom de classe, template arguments, etc. Il est bizarre que ce soit pris jusqu'à maintenant et ce n'est encore qu'en phase de proposition, mais nous y sommes. Soupir! J'espère vraiment que cela en fait en C++ 20 ou quoi que ce soit. –

+0

@underscore_d Malheureusement, cette proposition n'inclut pas d'équivalent 'using class', donc elle n'offre pas encore toute la flexibilité. – negamartin

+0

@negamartin Que cherchez-vous? S'il vous plaît fournir un exemple. Le point principal est que 'namespace class' résoudra cette répétition pour l'auteur de la classe, qui est la perspective à partir de laquelle le PO a posé cette question. Pendant ce temps, les utilisateurs de la classe peuvent faire quelque chose comme 'using tiny_type = SomeNamespace :: SomeOtherNamespace :: AHugeClassName;'. Que voulez-vous de plus? –

Répondre

0

Je ne suis pas sûr que je vous recommande, mais vous pourrait utiliser une macro comme:

#define sn LongUnderstandableName 

void sn::MethodA(parameters) { ... } 
int sn::MethodB(parameters) { ... } 

et ainsi de suite. L'un des points négatifs des macros est qu'elles ne respectent pas la portée, mais dans ce cas, la portée que vous voulez (apparemment) est le fichier source, qui correspond (assez étroitement) à la portée d'une macro.

+1

+1, c'est une solution rapide, mais je ne le recommanderais pas non plus. C'est une recette pour le désastre. –

+1

Oui - Je serais beaucoup plus susceptible de le définir comme une macro dans l'éditeur, donc je n'ai qu'à taper le nom court, et il est automatiquement étendu à la vraie - mais personne d'autre ne doit être conscient de cela . –

+0

Vous pourriez utiliser un typedef à la place. –

0

Eh bien, oui, une fois que vous avez compris les espaces de noms.

Au lieu de nommer votre MyBonnieLiesOverTheOcean de classe, au lieu définir les paramètres suivants:

namespace My { namespace Bonnie { namespace LiesOverThe { 
    class Ocean { ... }; 
} } } 

Maintenant, lorsque vous définissez vos méthodes, vous mettez les mêmes espaces de noms dans le fichier entier, et vous écrivez:

Ocean::SomeMethod() ... 

Lorsque vous utilisez la classe en dehors de tous les espaces de noms, il est:

My::Bonnie::LiesOverThe::Ocean 

Si vous avez besoin de référencer beaucoup de choses à partir d'un autre espace de noms dans un fichier source, vous pouvez utiliser la directive 'use' pour tromper les préfixes.

+0

C'est une bonne idée, mais il faut sucer pour taper tous ces: :) –

+0

Eh bien, c'est pourquoi nous avons «utiliser». – bmargulies

+0

Ah ok, oui. Vous pouvez dire 'use My :: Bonnie :: LiesOverThe'; et ensuite travailler sur le dernier niveau d'imbrication –

1

À l'intérieur des méthodes des classes, vous pouvez utiliser le nom sans qualification, de toute façon: il suffit de supprimer le préfixe longUnderstandableName::.

Dans les fonctions à l'intérieur du fichier source de la classe qui ne sont pas des méthodes, je vous suggère d'introduire des fonctions inline statique fichier entier, comme ceci:

inline type MethodA(type param){ 
    return longUnderstandableName::MethodA(param); 
} 

Ensuite, vous pouvez appeler METHODA non qualifié; en raison de la nature en ligne, cela ne coûtera probablement pas de temps d'exécution.

+0

Oui, mais cela vous oblige à définir la méthode dans l'en-tête, ce qui est inefficace car cela force la recompilation de tous les clients à chaque fois que la classe change. –

+1

Non, cela ne vous force pas à le faire.En fait, vous ne devez pas définir la méthode dans l'en-tête, mais en haut du fichier source de la classe, sinon le raccourci sera globalement disponible, ce que l'OP ne veut pas. –

+1

Fonctionne uniquement pour les membres statiques. – Basilevs

11
typedef longUnderstandableName sn; 

Ensuite, vous pouvez définir les méthodes comme

void sn::MethodA() {} 
void sn::MethodB() {} 

et les utiliser comme

sn::MethodA(); 
sn::MethodB(); 

Cela ne fonctionne que si longUnderstandableName est le nom d'une classe. Cela fonctionne même si la classe est profondément intégrée dans un autre espace de noms.

Si longUnderstandableName est le nom d'un espace de noms, puis dans l'espace de noms (ou fichier source) où vous souhaitez utiliser les méthodes, vous pouvez écrire

using namespace longUnderstandableName; 

puis appeler des méthodes comme

MethodA(); 
MethodB(); 

Vous devez faire attention à ne pas utiliser un using namespace foo; dans les fichiers d'en-tête, car cela pollue tous les fichiers .cpp que nous avons dans le fichier d'en-tête #include, mais en utilisant un using namespace foo; en haut d'un .cpp fichier est définitivement autorisé et encouragé.

+0

Ça marche vraiment? Je veux dire typedef est une bouée de sauvetage pour faire des abbréviations, mais les déclarations ont généralement tendance à avoir besoin des noms d'origine. Avez-vous utilisé cette approche? – Basilevs

+0

@Basilevs: Les déclarations n'ont pas besoin des noms d'origine. Un typedef ne "crée pas un nouveau type" différent de l'ancien - il crée simplement un nouveau nom qui fait référence au même ancien type. Les gens utilisent cette approche tout le temps pour traduire quelque chose comme 'std :: map :: iterator' en quelque chose de plus court. (Et 'std :: map :: iterator' est généralement un' typedef' pour une classe qui est un détail d'implémentation dans la liste STL –

+0

Mais ce n'est pas une déclaration d'itérateur. vous avez cité une utilisation de type itérateur déclaré ailleurs – Basilevs