BG MVC Model View Controller eğitim serisi yayında...

Ana sayfa > Programlama > C++ Programlama > İsim alanları (Namespaces)

İsim alanları (Namespaces)

C++'da, isim alanlarını temel amacı, isim çakışmalarını önlemek için tanımlayıcıların isimlerini yerel olarak ifade etmektir. İsim alanları kullanılmadığında, farklı yerlerde kullanılan aynı isme sahip değişken, fonksiyon ve sınıflar arasında bir karışıklık yaşanmaktadır. C++ standart kütüphanesi std adlı isim alanı içinde tanımlı olduğundan, bu kütüphanede yer alan bildirimlerin, program içinde yapılan benzer isme sahip diğer bildirimlerle çatışması engellenmektedir. Her programda, bildirimlerimiz için ayrı isim alanları oluşturabiliriz.

İsim alanları kullanımı

İsim alanı oluşturmak için namespace anahtar kelimesini kullanabiliriz. İsim alanı tanımlayarak, global isim alanı içinde belirli bölge ayırmış oluruz.

İsim alanı oluşturmak için kullanılan genel yapı aşağıda gösterilmektedir:

namespace isim-alanı-adı {
  // Bildirimler
}

İsim alanı içinde yer alan bildirimler, tanımlandığı isim alanının kapsamında işlem görür.

Bir isim alanı içinde tanımlanan değişken, fonksiyon ve sınıflara isim alanı içinden doğrudan, isim alanı dışından ise isim alanın ismi :: işlemcisi ve erişim sağlanacak isim alanı üyesinin adı ile birlikte kullanılarak erişim sağlanır.

isim-alanı-adı::üye-adı;

Şimdi, isim alanı bildirimi ve kullanımını bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

// Global bildirimler
int id;

int kare_al(int deger)
{
  return deger * deger;
}

class sinif
{
  private:
    int priid;
  protected:
    int proid;
  public:
    int pubid;
    sinif(int pid1, int pid2, int pid3)
    {
      priid = pid1; proid = pid2; pubid = pid3;
    }
    void deger_goster()
    {
      cout << priid << " " << proid << " " << pubid << "\n";
    }
};

// İsim alanı bildirimi
namespace ns
{
  int id;

  int kare_al(int deger)
  {
    return deger * deger;
  }

  class sinif
  {
    private:
      int priid;
    protected:
      int proid;
    public:
      int pubid;
      sinif(int pid1, int pid2, int pid3)
      {
        priid = pid1; proid = pid2; pubid = pid3;
      }
      void deger_goster()
      {
        cout << priid << " " << proid << " " << pubid << "\n";
      }
  };
}

int main(void)
{
  // Global olarak tanımlanmış değişken, fonksiyon ve sınıf işlemleri
  sinif nes1(7, 21, 35);
  nes1.deger_goster();

  id = kare_al(21);
  cout << 21 << " değerinin karesi: " << id << "\n";

  // İsim alanı içinde tanımlanmış değişken, fonksiyon ve sınıf işlemleri
  ns::sinif nes2(9, 24, 38);
  nes2.deger_goster();

  ns::id = ns::kare_al(17);
  cout << 17 << " değerinin karesi: " << ns::id << "\n";

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

7 21 35
21 değerinin karesi: 441
9 24 38
17 değerinin karesi: 289

Program, önce global olarak, id adlı int bir değişken, parametre olarak geçirilen int bir değerin karesini geri döndüren kare_al() adlı bir fonksiyon ve priid adlı private int bir değişken, proid adlı protected int bir değişken, pubid adlı public int bir değişken, bu değişkenlere birer değer atayan bir constructor fonksiyonu ve değişken değerlerini ekrana yazan bir fonksiyon içeren sinif adlı bir sınıf bildirimi yapar. Sonra, yaptığı tüm bildirimleri aynı isme ve yapıya sahip olacak şekilde ns adlı isim alanı içinde yapar.

Önce, global olarak bildirimi yapılan sinif türünden bir nesne oluşturur ve nesne yoluyla deger_goster() fonksiyonu çağırarak sınıf kopyası içinde yer alan değişken değerlerini ekrana yazar. Global olarak tanımlanmış kare_al() fonksiyonu ile 21 değerinin karesini alarak yine global olarak tanımlanmış id int değişkenine atar ve değişken değerini ekrana yazar.

Sonra, aynı işlemleri, sadece değerleri değiştirerek, isim alanı içinde yer alan bildirimlerle gerçekleştirir. İsim alanı içinde yer alan değişken, fonksiyon ve sınıfa erişim için :: işlemcisi kullandığından, global olarak bildirimi yapılmış ve aynı isme sahip olan değişken, fonksiyon ve sınıf ile herhangi bir karışma olmaz.

Bir isim alanı içinde yer alan işlem satırlarında, aynı isim alanı içindeki verilere doğrudan erişim sağlanabilir. Bu durumu bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

namespace ns
{
  int id=21;

  void deger_goster(void)
  {
    cout << id; // id değişkenine doğrudan erişim sağlanır.
  }
}

int main(void)
{
  ns::deger_goster();

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

21

Program, bir isim alanı içinde id adlı int bir değişken ve bu değişken değerini ekrana yazan deger_goster() adlı bir fonksiyon bildirimi yapar. Bu fonksiyonu kullanarak değişken değerini ekrana yazar. Fonksiyon içinde id değişkenine doğrudan erişim sağlanmaktadır.

Using ifadesi kullanımı

Bir programda bildirimi yapılan isim alanları içinde yer alan tek bir üye veya tüm üyelere, isim alanı adı ve :: işlemcisi kullanmadan, doğrudan erişim sağlamak için, using ifadesi kullanabiliriz.

using namespace isim-alanı-adı;

using isim-alanı-adı::üye-adı;

Şimdi, using ifadesi kullanımını bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

namespace ns1
{
  int id;

  int kare_al(int deger)
  {
    return deger * deger;
  }

  class sinif
  {
    private:
      int priid;
    protected:
      int proid;
    public:
      int pubid;
      sinif(int pid1, int pid2, int pid3)
      {
        priid = pid1; proid = pid2; pubid = pid3;
      }
      void deger_goster()
      {
        cout << priid << " " << proid << " " << pubid << "\n";
      }
  };
}

namespace ns2
{
  int id1=7, id2=21;

  void deger_goster(void) {
    cout << id1 << " " << id2;
  }
}

using namespace ns1; // ns1 isim alanı içindeki tüm üyelerin erişime açılması
using ns2::id1;      // ns2 isim alanı içindeki id1 değişkeninin erişime açılması

int main(void)
{
  // ns1 isim alanı içindeki tüm üyelere isim alanı ve :: işlemcisi kullanmadan erişim
  sinif nes(9, 24, 38);
  nes.deger_goster();

  id = kare_al(17);
  cout << 17 << " değerinin karesi: " << id << "\n";

  // ns2 isim alanı içindeki id1 değişkenine isim alanı ve :: işlemcisi kullanmadan erişim
  id1 = 75;
  // ns2 isim alanı içindeki id2 değişkeni ve deger_goster() fonksiyonuna isim alanı ve :: işlemcisi kullanarak erişim
  ns2::id2 = 35;
  ns2::deger_goster();

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

9 24 38
17 değerinin karesi: 289
75 35

Program, ns1 adlı bir isim alanı içinde, id adlı int bir değişken, parametre olarak geçirilen int bir değerin karesini geri döndüren kare_al() adlı bir fonksiyon ve priid adlı private int bir değişken, proid adlı protected int bir değişken, pubid adlı public int bir değişken, bu değişkenlere birer değer atayan bir constructor fonksiyonu ve değişken değerlerini ekrana yazan bir fonksiyon içeren sinif adlı bir sınıf bildirimi yapar. Sonra, ns2 adlı bir isim alanı içinde, id1 ve id2 adlı iki adet int değişken ve bu değişken değerlerini ekrana yazan deger_goster() adlı bir fonksiyon bildirimi yapar.

Daha sonra, using ifadesini iki defa kullanarak, ns1 isim alanı içindeki tüm üyelerin ve ns2 isim alanı içindeki id1 değişkenini erişime açar.

Önce, ns1 isim alanı içindeki sinif türünden bir nesne oluşturur ve nesne yoluyla deger_goster() fonksiyonu çağırarak sınıf kopyası içinde yer alan değişken değerlerini ekrana yazar. ns1 isim alanı içinde tanımlanmış kare_al() fonksiyonu ile 17 değerinin karesini alarak yine ns1 isim alanı içinde tanımlanmış id int değişkenine atar ve değişken değerini ekrana yazar.

Sonra, :: işlemcisini kullanmadan, ns2 isim alanı içindeki id1 değişkenine 75 değerini atar. :: işlemcisini kullanarak, ns2 isim alanı içindeki deger_goster() fonksiyonu ile id1 ve id2 değişken değerlerini ekrana yazar.

İsimsiz (Anonim) isim alanları

İsimsiz (Anonim) isim alanlarını kullanarak, sadece tek bir kaynak kod dosyada kullanmak istediğimiz üyeler tanımlayabiliriz.

İsimsiz isim alanları oluşturmak için kullanılan genel yapı aşağıda gösterilmektedir:

namespace {
  // Bildirimler
}

Bir dosya içinde tanımlanan isimsiz isim alanında yer alan değişken, fonksiyon ve sınıflara, aynı dosyadan doğrudan erişim sağlanabilir, ancak farklı dosyalardan hiç bir şekilde erişim sağlanamaz.

İsimsiz isim alanları içinde bildirimi yapılan değişkenler, static olarak bildirilen değişkenlerin yerine kullanılabilir.

Şimdi, isimsiz isim alanlarının kullanımını bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

namespace
{
  int id;

  int kare_al(int deger)
  {
    return deger * deger;
  }

  class sinif
  {
    private:
      int priid;
    protected:
      int proid;
    public:
      int pubid;
      sinif(int pid1, int pid2, int pid3)
      {
        priid = pid1; proid = pid2; pubid = pid3;
      }
      void deger_goster()
      {
        cout << priid << " " << proid << " " << pubid << "\n";
      }
  };
}

int main(void)
{
  // İsimsiz isim alanı içindeki tüm üyelere doğrudan erişim
  sinif nes(9, 24, 38);
  nes.deger_goster();

  id = kare_al(17);
  cout << 17 << " değerinin karesi: " << id;

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

9 24 38
17 değerinin karesi: 289

Program, isimsiz bir isim alanı içinde, id adlı int bir değişken, parametre olarak geçirilen int bir değerin karesini geri döndüren kare_al() adlı bir fonksiyon ve priid adlı private int bir değişken, proid adlı protected int bir değişken, pubid adlı public int bir değişken, bu değişkenlere birer değer atayan bir constructor fonksiyonu ve değişken değerlerini ekrana yazan bir fonksiyon içeren sinif adlı bir sınıf bildirimi yapar.

İsimsiz isim alanı içindeki sinif türünden bir nesne oluşturur ve nesne yoluyla deger_goster() fonksiyonu çağırarak sınıf kopyası içinde yer alan değişken değerlerini ekrana yazar. İsim alanı içinde tanımlanmış kare_al() fonksiyonu ile 17 değerinin karesini alarak yine isim alanı içinde tanımlanmış id int değişkenine atar ve değişken değerini ekrana yazar.

Bir kaynak kod dosyasında isimsiz isim alanı içinde tanımlanan bir üye değere diğer bir kaynak kod dosyası içinden erişim sağlanamaz.

İç içe isim alanları

Bir isim alanı içinde yine bir isim alanı bildirimi yapabiliriz. İçte yer alan isim alanı üyelerine erişim için dıştaki ve içteki isim alanlarını adları ile :: işlemcisini iki defa veya using ifadesini kullanmamız gerekir.

Şimdi, içi içe bildirimi yapılmış isim alanlarının kullanımını bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

namespace ns1 {
  int id1=7;

  namespace ns2 {
    int id2=21;

    void deger_goster(void)
    {
      cout << "id1=" << id1 << " id2=" << id2 << "\n";
    }
  }

  void deger_goster(void)
  {
    cout << "id1=" << id1 << " id2=" << ns2::id2 << "\n";
  }
}

int main(void)
{
  ns1::id1 = 14;            // Dıştaki isim alan değişkenine erişim 
  ns1::ns2::id2 = 35;       // İçteki isim alan değişkenine erişim 

  ns1::deger_goster();      // Dıştaki isim alanı fonksiyonuna erişim 
  ns1::ns2::deger_goster(); // İçteki isim alanı fonksiyonuna erişim 

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

id1=14 id2=35
id1=14 id2=35

Program, ns1 adlı bir isim alanı içinde bir adet id1 adlı int değişken, ns2 adlı bir isim alanı ve ns1 ve ns2 isim alanları içindeki id1 ve id2 değişken değerlerini ekrana yazan deger_goster() adlı bir fonksiyon bildirimi yapar. ns2 adlı isim alanı içinde bir adet id2 adlı int değişken ve ns1 ve ns2 isim alanları içindeki id1 ve id2 değişken değerlerini ekrana yazan deger_goster() adlı bir fonksiyon bildirimi yapar.

ns1 isim alanı içindeki id1 değişkenine isim alanı adı ve :: işlemcisi ile, ns2 isim alanı içindeki id2 değişkenine ns1 ve ns2 isim alanlarının adları ile değişken adı arasında iki defa :: işlemcisi kullanarak erişim sağlar. İsim alanları içinde yer alan fonksiyonlara da aynı yöntemle erişim sağlayarak değişken değerlerini ekran yazar.

ns2 isim alanı içindeki fonksiyon her iki değişken değerine doğrudan erişim sağlarken, ns1 isim alanı içindeki fonksiyon ns2 isim alanı içindeki id2 değişkenine erişim sağlarken isim alanı adı ve :: işlemcisine ihtiyaç duyar.

std isim alanı

C++'da, tüm kütüphane bildirimleri std adlı isim alanında yer alır. Programlarda yer alan aşağıdaki satır ile std isim alanında yer alan değişken, fonksiyon, sınıf ve benzeri bildirimlere erişim sağlanır.

using namespace std;

Program using ifadesi ile tüm Standart C++ Kütüphanesinin yer aldığı std namespace isim alanını kullanacağını bildirir. Böylece, std:: ifadesini kullanmadan std isim alanında yer alan üyelere doğrudan erişim sağlanır.

Önce, std isim alanında yer alan üyelere :: işlemcisi ile erişim sağlanan bir örneği incelemeye çalışalım:


#include <iostream>

int main(void)
{
  int id=21;

  std::cout << "Değişken değeri: " << id << "\n";
  std::cout << "Değişken değerinin karesi: " << id*id;

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Değişken değeri: 21
Değişken değerinin karesi: 441

Program, id adlı int değişken bildirimi yapar. Değişken değerini ve karesini ekrana yazarken, cout komutuna std:: ifadesini kullanarak erişim sağlar.

Şimdi, std isim alanında yer alan üyelere dığrudan erişim sağlanan bir örneği incelemeye çalışalım:


#include <iostream>

using namespace std;

int main(void)
{
  int id=21;

  cout << "Değişken değeri: " << id << "\n";
  cout << "Değişken değerinin karesi: " << id*id;

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Değişken değeri: 21
Değişken değerinin karesi: 441

Program, id adlı int değişken bildirimi yapar. Değişken değerini ve karesini ekrana yazarken, cout komutuna doğrudan erişim sağlar.