Share via


Üst bilgi dosyaları (C++)

Değişkenler, işlevler, sınıflar vb. gibi program öğelerinin adlarının kullanılabilmesi için önce bildirilmesi gerekir. Örneğin, önce 'x' bildiriminde bulunmadan yalnızca yazamazsınız x = 42 .

int x; // declaration
x = 42; // use x

bildirimi, derleyiciye öğesinin bir int, , doubleişlevi veya başka bir class şey olup olmadığını bildirir. Ayrıca, her ad kullanıldığı her .cpp dosyasında (doğrudan veya dolaylı olarak) bildirilmelidir. Bir programı derlediğinizde, her .cpp dosyası bir derleme birimine bağımsız olarak derlenmiş olur. Derleyicinin diğer derleme birimlerinde hangi adların bildirileceği hakkında bilgisi yoktur. Başka bir deyişle, bir sınıf veya işlev ya da genel değişken tanımlarsanız, bunu kullanan her ek .cpp dosyasında bu şeyin bildirimini sağlamanız gerekir. Bu şeyin her bildirimi tüm dosyalarda tam olarak aynı olmalıdır. Bağlayıcı tüm derleme birimlerini tek bir programda birleştirmeye çalıştığında küçük bir tutarsızlık hatalara veya istenmeyen davranışlara neden olur.

C++, hata olasılığını en aza indirmek için üst bilgi dosyalarını bildirim içerecek şekilde kullanma kuralını benimsemiştir. Bildirimleri bir üst bilgi dosyasında yaparsınız, ardından her .cpp dosyasında veya bu bildirimi gerektiren diğer üst bilgi dosyalarında #include yönergesini kullanırsınız. #include yönergesi, derlemeden önce üst bilgi dosyasının bir kopyasını doğrudan .cpp dosyasına ekler.

Dekont

Visual Studio 2019'da C++20 modülleri özelliği, üst bilgi dosyaları için iyileştirme ve son değiştirme olarak kullanıma sunulmuştur. Daha fazla bilgi için bkz . C++'da modüllere genel bakış.

Örnek

Aşağıdaki örnek, bir sınıfı bildirmenin ve ardından farklı bir kaynak dosyada kullanmanın yaygın bir yolunu gösterir. üst bilgi dosyasıyla başlayacağız. my_class.h Bir sınıf tanımı içerir, ancak tanımın eksik olduğuna dikkat edin; üye işlevi do_something tanımlanmadı:

// my_class.h
namespace N
{
    class my_class
    {
    public:
        void do_something();
    };

}

Ardından bir uygulama dosyası oluşturun (genellikle .cpp veya benzer bir uzantıyla). my_class.cpp dosyasını çağıracak ve üye bildirimi için bir tanım sağlayacağız. .cpp dosyasında bu noktada my_class bildiriminin eklenmesi için "my_class.h" dosyası için std::coutbir #include yönerge ekliyoruz ve bildirimini çekmeyi de dahil <iostream> ediyoruz. Alıntıların kaynak dosyayla aynı dizindeki üst bilgi dosyaları için, açılı ayraçların ise standart kitaplık üst bilgileri için kullanıldığını unutmayın. Ayrıca, birçok standart kitaplık üst bilgisinde .h veya başka bir dosya uzantısı yoktur.

Uygulama dosyasında isteğe bağlı olarak, "my_class" veya "cout" ifadelerinin her birini "N::" veya "std::" ile nitelemekten kaçınmak için bir using deyimi kullanabiliriz. Üst bilgi dosyalarınıza deyimler koymayın using !

// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library

using namespace N;
using namespace std;

void my_class::do_something()
{
    cout << "Doing something!" << endl;
}

Artık başka bir .cpp dosyasında kullanabiliriz my_class . Derleyicinin bildirimi çekmesi için üst bilgi dosyasını #include. Derleyicinin bilmesi gereken tek şey, my_class adlı do_something()genel üye işlevine sahip bir sınıf olmasıdır.

// my_program.cpp
#include "my_class.h"

using namespace N;

int main()
{
    my_class mc;
    mc.do_something();
    return 0;
}

Derleyici her .cpp dosyasını .obj dosyalarına derlemeyi tamamladıktan sonra ,obj dosyalarını bağlayıcıya geçirir. Bağlayıcı nesne dosyalarını birleştirdiğinde my_class için tam olarak bir tanım bulur; my_class.cpp için üretilen .obj dosyasındadır ve derleme başarılı olur.

Korumaları dahil et

Genellikle, üst bilgi dosyalarının tek bir .cpp dosyasına birden çok kez eklenmediğinden emin olmak için bir include guard veya #pragma once yönergesi vardır.

// my_class.h
#ifndef MY_CLASS_H // include guard
#define MY_CLASS_H

namespace N
{
    class my_class
    {
    public:
        void do_something();
    };
}

#endif /* MY_CLASS_H */

Üst bilgi dosyasına ne konur?

Bir üst bilgi dosyası birden çok dosya tarafından dahil edilebileceğinden, aynı ada sahip birden çok tanım üretebilecek tanımlar içeremez. Aşağıdakilere izin verilmez veya çok kötü bir uygulama olarak kabul edilir:

  • ad alanında veya genel kapsamda yerleşik tür tanımları
  • satır içi olmayan işlev tanımları
  • const olmayan değişken tanımları
  • toplama tanımları
  • adlandırılmamış ad alanları
  • using yönergeleri

yönergesinin using kullanılması mutlaka bir hataya neden olmaz, ancak ad alanını doğrudan veya dolaylı olarak bu üst bilgiyi içeren her .cpp dosyasında kapsama getirdiğinden bir soruna neden olabilir.

Örnek üst bilgi dosyası

Aşağıdaki örnek, bir üst bilgi dosyasında izin verilen çeşitli bildirim ve tanım türlerini gösterir:

// sample.h
#pragma once
#include <vector> // #include directive
#include <string>

namespace N  // namespace declaration
{
    inline namespace P
    {
        //...
    }

    enum class colors : short { red, blue, purple, azure };

    const double PI = 3.14;  // const and constexpr definitions
    constexpr int MeaningOfLife{ 42 };
    constexpr int get_meaning()
    {
        static_assert(MeaningOfLife == 42, "unexpected!"); // static_assert
        return MeaningOfLife;
    }
    using vstr = std::vector<int>;  // type alias
    extern double d; // extern variable

#define LOG   // macro definition

#ifdef LOG   // conditional compilation directive
    void print_to_log();
#endif

    class my_class   // regular class definition,
    {                // but no non-inline function definitions

        friend class other_class;
    public:
        void do_something();   // definition in my_class.cpp
        inline void put_value(int i) { vals.push_back(i); } // inline OK

    private:
        vstr vals;
        int i;
    };

    struct RGB
    {
        short r{ 0 };  // member initialization
        short g{ 0 };
        short b{ 0 };
    };

    template <typename T>  // template definition
    class value_store
    {
    public:
        value_store<T>() = default;
        void write_value(T val)
        {
            //... function definition OK in template
        }
    private:
        std::vector<T> vals;
    };

    template <typename T>  // template declaration
    class value_widget;
}