C ++ 'da "kullanma" bildiriminin kapsamı nedir?


100

Yerel isim alanına std :: string ve std :: vector eklemek için C ++ 'kullanma' bildirimini kullanıyorum (gereksiz 'std ::' s yazmayı kaydetmek için).

using std::string;
using std::vector;

class Foo { /*...*/ };

Bu beyannamenin kapsamı nedir? Bunu bir başlıkta yaparsam, bu 'using' bildirimlerini başlığı içeren her cpp dosyasına enjekte eder mi?


18
Buradaki diğer cevaplardan anlaşılmaması durumunda: - İçerme dosyası / başlığında dosya kapsamına bir usingbildirim (veya usingyönerge) koymayın ! Bu, başlığın kullanıcıları için baş ağrısına neden olacaktır.
Michael Burr

Aslında, bir koymayın usingbeyanı (a fortiori yönergesi bir başlık olarak) hiç , hatta bir ad alanı içinde! Bunun neden olduğu sorunlar için bir ad alanı içinde bildirim kullanımının kapsamına bakın .
Nils von Barth

@NilsvonBarth: Bu biraz fazla basitleştirilmiş. Kullanılması usingsınıf ve işlev kapsamında tartışılan sorun ile ilgili güvenlidir.
Sebastian Mach


ADL C ++ arama özelliği hakkında bilgi edinmek isteyebilirsiniz .
Alexis Wilke

Yanıtlar:


59

C ++ 'da bir başlık dosyasını #include yaptığınızda, başlık dosyasının tüm içeriğini kaynak dosyaya eklediğiniz noktaya yerleştirir. Dolayısıyla, usingbeyanı olan bir dosyanın dahil edilmesi, usingbeyanı bu başlık dosyasını içeren her dosyanın üstüne yerleştirmekle aynı etkiye sahiptir .


51
... bu genellikle kötü bir şeydir.
Catskul

17
Ancak usingbeyanı bir namespacead alanının kapsamı ile sınırlı bir içine koyarsanız , genellikle tamamdır (özel ihtiyaçlarınız ve tarzınız hakkındaki olağan uyarılarla).
Sıfır

1
... ancak bir ad alanının içine koyarsanız, bunu normalde kötü bir fikir olan bir şeyin etrafından dolaşmak için yapmadığınızdan emin olun, örneğin, ad alanı Y'nin dışında bildirilmiş sınıf yöntemlerini diğerinin içine sığdıramazsınız. isim alanı X, sadece yerel olarak X isim alanını kullanabilirsiniz. Bu yüzden ilk etapta isim-alanı :: çözücüler kullanıyoruz. Bir makro (kolayca kod kokularına neden olabilir) ya da daha iyisi, yalnızca ad alanını kullanacağınız kendi kaynağı .cpp'ye ayırın.
osirisgothra

1
Bu ve benzeri cevaplar iyi bir tavsiye olsa da soruyu cevaplamazlar.
Emile Cormier

116

usingBildirimi dışarıda tutacak başlık dosyalarıyla ilgili özel bir şey yoktur . Derleme başlamadan önce basit bir metin ikamesi.

Bir usingbildirimi bir kapsamla sınırlayabilirsiniz :

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}

12
Bunu bir işlevin içinde kullanabileceğimi hiç düşünmemiştim!
Agostino

1
Hepsi bir "birleştirici" tipi dosya tarafından kullanılan bir sürü ad alanım var ve gmock birim testi çok sıkıcıydı çünkü her test belirli bir ad alanından şeyler kullanıyordu ve her değişkeni nitelemem gerektiğini düşündüm. Kullanılması usingbir işlev içinde (hatta bir GTEST TESTmakro!) Çok daha iyi hayatımı yapar!
dwanderson

54

Using ifadesinin kapsamı, kodun neresinde bulunduğuna bağlıdır:

  • Bir dosyanın en üstüne yerleştirildiğinde, bu dosya boyunca kapsamı vardır.
  • Bu bir başlık dosyasıysa, bu başlığı içeren tüm dosyalarda kapsamı olacaktır. Genel olarak, beklenmedik yan etkileri olabileceğinden bu " iyi bir fikir değildir "
  • Aksi takdirde, using ifadesi, oluştuğu noktadan bloğun sonuna kadar onu içeren blok içinde kapsama sahiptir. Bir yönteme yerleştirilirse, kapsamı o yöntem içinde olacaktır. Bir sınıf tanımının içine yerleştirilirse, o sınıf içinde kapsamı olacaktır.

5
usingSınıf kapsamına bir ifade eklemenin mümkün olmadığını düşündüm ...? Her std::yerde yazmaktan kaçınmak istediğim için OP ile aynı soruyu sormuştum . Akıllı işaretçilerle çok sayıda vektör kullanan sınıflarım var ve beş karakterli std::ön ek çok fazla satır uzunluğu ekliyor - ki okumaları daha kötü buluyorum. Bu nedenle using, sınıfı içeren ad alanı içindeki bir yönergenin uygun olup olmadığını merak ediyordum. (Bir başlık içinde olsa bile.)
thomthom

5
Peki ya a kapsamına girerse namespace { ... }?
einpoklum

Yani tamamen yazabilirsiniz: {ad alanı blabla kullanarak; sınıf blah {}; } ve bu kullanım sadece sınıf için geçerli olacak?
Dinaiz

8

Kapsam, kullanım bildiriminin içinde bulunduğu kapsamdır.

Bu küresel kapsamsa, o zaman küresel kapsamda olacaktır. Bir başlık dosyasının genel kapsamındaysa, başlığı içeren her kaynak dosyanın genel kapsamında olacaktır.

Bu nedenle, genel tavsiye, başlık dosyalarının global kapsamında bildirimleri kullanmaktan kaçınmaktır .


3
Bu yeterince güçlü değil. Kaçınmayı Don't
Martin York

1
BUt, yapmamaktan daha güçlüdür. "Diğer arabalara çarpmaktan kaçının"
bobobobo

6

Belirtilen durumda, dosya ("çeviri birimi"), yani evet, onu içeren her dosya.

Ayrıca using ifadesini sınıfın içine de koyabilirsiniz, bu durumda, yalnızca o sınıf için geçerlidir.

Genel olarak, bir başlıkta bir ad alanı belirtmeniz gerekiyorsa, genellikle gerekli olan her tanımlayıcıyı tam olarak nitelendirmek en iyisidir.


O Not usingbunu getirmek kullanamazsınız örneğin - bir sınıfta beyan bir sınıf dışında aynı şekilde davranmaz coutyerine std::coutsınıfın kapsam içine.
Sıfır

2

Bu doğru. Kapsam, usingbildirimi kullanan modüldür . Bir modülün içerdiği herhangi bir başlık dosyasında usingbildirimler varsa, bu bildirimlerin kapsamı o modülün yanı sıra aynı başlıkları içeren diğer modüller olacaktır.


1

"Yapma" dedikleri zaman oldukça yetersiz kalan birkaç yorum var. Bu çok sert, ama her şeyin yolunda olduğunu anlamalısın.

Yazmak using std::stringasla tamam değildir. Yazma using ImplementationDetail::Fooo başlık ImplementationDetail beyan kendi başlığında, :: Foo kullanarak beyanı senin ad olur moreso eğer Tamam olabilir. Örneğin

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
Başlığın kullanıcısı daha sonra yazabilirMyNS::Foo
Peter Remmers

Daha iyi bir örnek using boost::posix_time::ptime. Eminim kullanıcı yazabilir MyNS::ptimeama bu dünyanın sonu değil ve gibi işlevlere sahip olmanın rahatlığı ile dengelenebilir MyFunction(ptime a, ptime b).
Sıfır

5
Neden olduğunu using std::stringasla tamam mı? Çok sayıda std::önek kaydetmek için kendi ad alanınızda bile mi?
thomthom

@thomthom kendi ad alanınız gibi bir kapsamda sarıldığında sorun yok.
jcoffland
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.