Sınıf kodunu başlık ve cpp dosyasına ayırma


170

Basit bir sınıfın uygulama ve bildirimler kodunu yeni bir başlık ve cpp dosyasına nasıl ayıracağım konusunda kafam karıştı. Örneğin, aşağıdaki sınıfın kodunu nasıl ayırırım?

class A2DD
{
  private:
  int gx;
  int gy;

  public:
  A2DD(int x,int y)
  {
    gx = x;
    gy = y;
  }

  int getSum()
  {
    return gx + gy;
  }
};

12
Sadece birkaç yorum: Yapıcı, vücuttaki üyeleri ayarlamak yerine her zaman bir başlatma listesi kullanmalıdır. İyi ve basit bir açıklama için bkz. Codeguru.com/forum/showthread.php?t=464084 Ayrıca, en azından çoğu yerde, genel alanın en üstte olması gelenekseldir. Hiçbir şeyi etkilemez, ancak ortak alanlar sınıfınızın belgeleri olduğundan, en üstte olması mantıklıdır.
martiert

2
@martiert Having public:üstündeki üye olabilir bir etkileyen çok ama üyeler arasında bağımlılıkları sipariş etmişti ve üyeleri beyanı ;-) sırasına göre başlatıldı olduğunu henüz farkında değildi - Kullanıcı onlara bu tavsiyesine göre hareket ederse,
underscore_d

1
@underscore_d bu doğru. Ama sonra tekrar, hepimiz hata olarak uyarılarla ve aklınıza gelebilecek tüm uyarılarla derliyoruz, değil mi? Bu en azından bunu berbat ettiğinizi söyler, ancak evet, insanlar küçük uyarılara yol
açarlar

@martiert İyi bir nokta, uyarılar üreten tür unuttum - eğer sadece uyarılar çoğu tarafından okundu :-) Onları kullanmak ve hepsini kodlamaya çalışın. Birkaçı kaçınılmaz - bu yüzden 'uyarı için teşekkürler, ama ne yaptığımı biliyorum!' Diyorum. - ancak çoğu daha sonra karışıklığı önlemek için en iyi şekilde sabitlenir.
underscore_d

En üstte kamusal alanlara sahip olmak sadece bir tarz, maalesef çok fazla kişinin benimsediğini düşünüyorum. Ayrıca, @martiert'in belirttiği gibi bazı şeyleri aklınızda bulundurmanız gerekir.
Vassilis

Yanıtlar:


233

Sınıf bildirimi başlık dosyasına girer. #ifndefDahil etme korumalarını eklemeniz önemlidir veya bir MS platformundaysanız da kullanabilirsiniz #pragma once. Ayrıca özel atlandı, varsayılan olarak C ++ sınıf üyeleri özeldir.

// A2DD.h
#ifndef A2DD_H
#define A2DD_H

class A2DD
{
  int gx;
  int gy;

public:
  A2DD(int x,int y);
  int getSum();

};

#endif

ve uygulama CPP dosyasına gider:

// A2DD.cpp
#include "A2DD.h"

A2DD::A2DD(int x,int y)
{
  gx = x;
  gy = y;
}

int A2DD::getSum()
{
  return gx + gy;
}

53
Şablon programlama yapıyorsanız, derleyicinin derleme anında doğru kodu somutlaması için her şeyi .h dosyasında tutmanız gerektiğini unutmayın.
linello

2
#ifndefbaşlıkta bir şeyler var mı?
Ferenc Deak

4
Bu, başlık dosyanızı içeren tüm dosyaların özel üyeleri "göreceği" anlamına gelir. Örneğin bir lib ve başlığını yayınlamak istiyorsanız, sınıfın özel üyelerini mi göstermelisiniz?
Gauthier

1
Hayır, harika özel uygulama deyimi var: en.wikipedia.org/wiki/Opaque_pointer Uygulama ayrıntılarını gizlemek için kullanabilirsiniz.
Ferenc Deak

3
“Sınıf bildirimi başlık dosyasına giriyor” ifadesiyle küçük nitpick. Bu gerçekten bir bildiridir, ancak aynı zamanda bir tanımdır, ancak ikincisi öncekini içerdiğinden, sınıf tanımının başlık dosyasına girdiğini söylemeyi tercih ederim. Çeviri biriminde, sınıfın tanımını değil üye işlevlerinin tanımını görürsünüz. Katılıyorum, bu küçük bir düzenlemeye değer olabilir mi?
lubgr

17

Genel olarak .h dosyanız, tüm verileriniz ve tüm yöntem bildirimleriniz olan sınıf savunmasını içerir. Sizin durumunuzda böyle:

A2DD.h:

class A2DD
{
  private:
  int gx;
  int gy;

  public:
  A2DD(int x,int y);    
  int getSum();
};

Ve sonra .cpp dosyanız şu yöntemlerin uygulamalarını içerir:

A2DD.cpp:

A2DD::A2DD(int x,int y)
{
  gx = x;
  gy = y;
}

int A2DD::getSum()
{
  return gx + gy;
}

7

Konuyu daha geniş bir şekilde araştırırken bu soruyu tökezleyen okuyucuların, sadece projenizi dosyalara bölmek istediğinizde kabul edilen yanıt prosedürünün gerekli olmadığını belirtmek önemlidir. Yalnızca tekli sınıfların birden fazla uygulamasına ihtiyacınız olduğunda gereklidir. Sınıf başına uygulamanız bir ise, her biri için yalnızca bir başlık dosyası yeterlidir.

Bu nedenle, kabul edilen yanıtın örneğinden sadece bu bölüme ihtiyaç vardır:

#ifndef MYHEADER_H
#define MYHEADER_H

//Class goes here, full declaration AND implementation

#endif

#İfndef vb. Önişlemci tanımları birden çok kez kullanılmasına izin verir.

PS. C / C ++ 'aptal' ve #include sadece "bu metni bu noktaya dök" demenin bir yolu olduğunu fark edince konu daha da netleşiyor.


bunu "split" dosyaları koyarak yapabilir misiniz .cpp, ya da .hbu kod düzenleme yöntemi için sadece gerçekten "iyi" mi?
Benny Jobigan

1
Bazı projelerin başlık ve (tek) uygulama dosyalarını, uygulamaların kaynak kodunu göstermeden başlık dosyalarını kolayca dağıtabilmeleri için böldüklerini düşündüm.
Carl G

Ben aslında C ++ öğrendim sonra C # yıl önce geçti ve son zamanlarda tekrar C ++ bir sürü yapıyor ve dosyaları ne kadar can sıkıcı ve sinir bozucu olduğunu unuttum ve sadece her şeyi koyarak başladı unuttum çünkü bunu işaret sevindim Bu bulduğumda bunu yapmak için değil iyi nedenler veren birini arıyorlardı. @CarlG'nin iyi bir noktası var, ancak bu senaryo dışında hepsini satır içi yapmanın yolunun olduğunu düşünüyorum.
Peter Moore

6

Temel olarak işlev bildirimi / tanımlarının değiştirilmiş bir sözdizimi:

a2dd.h

class A2DD
{
private:
  int gx;
  int gy;

public:
  A2DD(int x,int y);

  int getSum();
};

a2dd.cpp

A2DD::A2DD(int x,int y)
{
  gx = x;
  gy = y;
}

int A2DD::getSum()
{
  return gx + gy;
}

5

A2DD.h

class A2DD
{
  private:
  int gx;
  int gy;

  public:
  A2DD(int x,int y);

  int getSum();
};

A2DD.cpp

  A2DD::A2DD(int x,int y)
  {
    gx = x;
    gy = y;
  }

  int A2DD::getSum()
  {
    return gx + gy;
  }

Fikir, tüm işlev imzalarını ve üyeleri başlık dosyasında tutmaktır.
Bu, diğer proje dosyalarının uygulamayı bilmeden sınıfın nasıl göründüğünü görmesini sağlar.

Bunun yanı sıra, uygulamaya başlık yerine başka başlık dosyaları da ekleyebilirsiniz. Başlık dosyanızda hangi başlıklar varsa üstbilgi dosyanızı içeren başka herhangi bir dosyaya dahil edilecekse (devralınacak) bu önemlidir.


4

Beyanları başlık dosyasında bırakırsınız:

class A2DD
{
  private:
  int gx;
  int gy;

  public:
    A2DD(int x,int y); // leave the declarations here
    int getSum();
};

Ve tanımları uygulama dosyasına koyun.

A2DD::A2DD(int x,int y) // prefix the definitions with the class name
{
  gx = x;
  gy = y;
}

int A2DD::getSum()
{
  return gx + gy;
}

İkisini karıştırabilirsiniz ( getSum()örneğin tanımı başlıkta bırakın ). Bu yararlıdır çünkü derleyiciye örneğin inlining konusunda daha iyi bir şans verir. Ancak bu, uygulamanın (başlıkta bırakılırsa) değiştirilmesinin, başlık içeren diğer tüm dosyaların yeniden oluşturulmasını tetikleyebileceği anlamına da gelir.

Şablonlar için hepsini başlıklarda tutmanız gerektiğini unutmayın.


1
Özel üyelerin ve işlevlerin başlık dosyasına yerleştirilmesi, uygulama ayrıntılarının sızdırılması olarak değerlendirilmez mi?
Jason

1
@ Jason, bir çeşit. Bunlar gerekli uygulama detaylarıdır. Örneğin, bir sınıfın yığın üzerinde ne kadar yer tüketeceğini bilmek zorundayım. Diğer derleme birimleri için işlev uygulamaları gerekli değildir.
Paul Draper

1

Genellikle başlık dosyasına yalnızca bildirimler ve gerçekten kısa satır içi işlevler koyarsınız:

Örneğin:

class A {
 public:
  A(); // only declaration in the .h unless only a short initialization list is used.

  inline int GetA() const {
    return a_;
  }

  void DoSomethingCoplex(); // only declaration
  private:
   int a_;
 };

0

Genel bir cevap için oldukça basit olduğu için örneğinizden bahsetmeyeceğim (örneğin, bunları başlığa uygulamanızı sağlayan şablonlanmış işlevler içermiyor), temel kural olarak takip ettiğim şey pimpl deyim

Daha hızlı derleme süreleri ve sözdizimsel şeker aldığınızda oldukça faydaları var:

class->member onun yerine class.member

Tek dezavantajı, ödediğiniz ekstra işaretçidir.

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.