2011-12-26 2 views
3

Я читал разные статьи и руководства по файлам заголовков. Я понимаю, что заголовки служат для сохранения «интерфейса» от реализации. (и другие вещи, как оптимизация компиляции)Заголовки C++, связанные с классами

Что я до сих пор не понимаю, и на самом деле не могу обдумать его вокруг, всегда ли вы используете заголовки? Я знаю, что вы можете писать блоки кода внутри самого файла заголовка. Но вот где я заблудился.

Когда я смотрю видеоурок, люди просто определяют функции своим телом в файле заголовка. Тогда в другой статье определяются только функции (я предполагаю, что это идея интерфейса).

На данный момент я делаю простой класс с именем Color. реализация:

/* 
* File: Color.cpp 
* Author: Sidar 
* 
* Created on 26 december 2011, 16:02 
*/ 

#include <stdio.h> 

#include "Color.h" 

Color::Color() { 

reset(); 
} 

Color::Color(const Color& orig) { 

a = orig.a; 
r = orig.r; 
g = orig.g; 
b = orig.b; 
} 

void Color::reset() 
{ 
    a = 0; 
    r = 0; 
    g = 0; 
    b = 0; 
} 

Color::Color(unsigned int r, unsigned int g, unsigned int b, unsigned int a) 
{ 
    this->r = r; 
    this->g = g; 
    this->b = b; 
    this->a = a; 
} 

Color::~Color() { 
    r = 0; 
    g = 0; 
    b = 0; 
} 

//getters____________________________ 
unsigned int Color::getRed() const 
{ 
    return r; 
} 

unsigned int Color::getBlue() const 
{ 
    return b; 
} 

unsigned int Color::getGreen() const 
{ 
    return g; 
} 

unsigned int Color::getAlpha() const 
{ 
    return a; 
} 

//setters____________________________ 

void Color::setRed(unsigned int r) 
{ 
    if(r > 255)r = 255; 
    if(r < 0)r = 0; 

    this->r = r; 
} 


void Color::setGreen(unsigned int g) 
{ 
    if(g > 255)g = 255; 
    if(g < 0)g = 0; 

    this->g = g; 
} 

void Color::setBlue(unsigned int b) 
{ 
    if(b > 255)b = 255; 
    if(b < 0)b = 0; 

    this->b = b; 
} 

void Color::setAlpha(unsigned int a) 
{ 
if(a > 255)a = 255; 
if(a < 0)a = 0; 

this->a = a; 
} 

unsigned int Color::color() 
{ 
    return (int)a << 24 | (int)r << 16 | (int)g << 8 | (int)b << 0; 
    } 

и здесь заголовок

/* 
* File: Color.h 
* Author: Sidar 
* 
* Created on 26 december 2011, 16:02 
*/ 

#ifndef COLOR_H 
#define COLOR_H 
#include <string> 

class Color { 
public: 

    Color(); 
    Color(const Color& orig); 
    Color(unsigned int r,unsigned int g,unsigned int b, unsigned int a); 

    virtual ~Color(); 
    //____________________ 
    void setRed(unsigned int r); 
    unsigned int getRed()const; 
    //____________________ 
    void setBlue(unsigned int b); 
    unsigned int getBlue()const; 
    //____________________ 
    void setGreen(unsigned int g); 
    unsigned int getGreen()const; 
    //____________________ 
    void setAlpha(unsigned int a); 
    unsigned int getAlpha()const; 
    //____________________ 
    unsigned int color(); 

    void reset(); 

private: 

    unsigned int r; 
    unsigned int b; 
    unsigned int g; 
    unsigned int a; 


}; 

#endif /* COLOR_H */ 

Этот код работает, я не получаю никаких ошибок. Но является ли это общей идеей заголовков и файлов cpp? И мой второй вопрос: Я много читал, что при использовании шаблонов проще всего реализовать код внутри заголовка. Я понимаю это (чтобы предотвратить множество реализаций для чего-то, что должно быть таким общим). Но есть ли другие ситуации? Я слишком долго ломаю голову над этим. Не из примеров, которые я встретил, дал мне конкретный ответ. И это действительно на моих нервах = (

Спасибо за ваше время,

Sidar

Edit: Я просто понял, я устанавливаю значение RGB в деструкторе ... LOL. Так что да, я знаю об этом =)

ответ

4

Вы не «всегда» ничего не делаете, все зависит от обстоятельств, ваших целей и стандартов кодирования вашей группы или организации.

C++ - это очень гибкий язык, который позволяет делать и организовывать различные способы.

Некоторые причины отдельные файлы реализации могут быть использованы:

  1. Чтобы сохранить реализацию отделенный от интерфейса, как вы предложить

  2. Чтобы ускорить время компиляции

  3. Для обработки циклические зависимости

  4. Итак, вы можете отправить бинар у библиотеки только с файлами заголовков и не исходный код основной

Некоторые причины, по которым вы не могли бы хотеть отдельные файлы реализации:

  1. Вы можете использовать шаблоны, которые «обычно» должны быть определенные с помощью объявлений

  2. Вы НЕ хотите, чтобы реализация была отделена от интерфейса. В во многих случаях это упрощает понимание, поскольку у вас нет , чтобы перевернуть назад и вперед между заголовком и файлом реализации. Это может быть контрпродуктивным, если вы имеете дело с большими классами с многими методами.

  3. Вы хотите, чтобы ваш код был встроен в компилятор как .

  4. Вы создаете библиотеку кодов, для которой вы не хотите, чтобы пользователь беспокоился о строительстве. Большинство библиотек Boost - это , где вам не нужно использовать систему Boost build, которая может быть довольно сложной, но вместо этого вы просто включаете в свой код файлы заголовков , и это все, что вам нужно. сделать их использовать.


Я обычно начинаю работу над новым классом, определив всю логику в файле заголовок. А потом, когда класс будет завершен или когда он начнет заполняться в заголовочном файле, я начну переводить логику в отдельный файл реализации.Это делается исключительно для того, чтобы максимально использовать мое время, так как я могу быстрее справляться и с меньшим количеством ошибок, когда вижу все в одном файле.

Следует также отметить, что вам необязательно использовать файлы заголовков вообще. Вы можете определить некоторые классы непосредственно в ваших .cpp-файлах. Это часто делается для частных классов, которые никогда не будут использоваться вне этого .cpp-файла.

+0

Благодарим вас за ответ. Теперь это имеет больше смысла. Наверное, мне просто нужно сделать больше C++, чем Java/C#, чтобы привыкнуть к нему. Я должен больше узнать о тех встроенных функциях. – Sidar

0

Хорошо, прежде всего, вот ответ, почему шаблоны могут быть реализованы только в заголовочных файлах:

Why can templates only be implemented in the header file?

Это не потому, что это родовое, это потому, что компиляторы фактически обрабатывают шаблоны. Если вы не получите объяснение, сообщите мне :).

+0

О да, возможно, это неправильно, но я понимаю =)! – Sidar

0

Если вы помещаете реализации метода в файл заголовка, компилятор C++ может выбрать встроенный код на сайтах-контактах. Это может быть более эффективным.

Если у вас есть класс, определенный полностью в файле заголовка, вам не нужен файл .cpp, делающий вещи (если реализация коротка) немного легче понять.

+0

Но когда мне нужен CPP-файл, например, мой код? Вот где я просто остановился. – Sidar

+0

Это вопрос вкуса. –

+0

ха-ха, тебе не легче. Итак, действительно ли нет стандартов о том, как это сделать? Соглашение существует только в группах, с которыми вы работаете? – Sidar

0

Файлы заголовков не используются для «отделяния интерфейса» от реализации, они уже содержат множество деталей реализации, если вы не используете идиом pimpl. Это другая тема, и это можно сделать на любом языке, который не имеет «заголовочного» файла, такого как C# и Java.

Их реальное использование исходит из того факта, что, когда компилятор должен выделить место для экземпляра класса, он должен знать его размер. Чтобы вычислить размер, для этого класса требуется полное объявление. Поскольку вы, вероятно, собираетесь использовать экземпляр этого класса среди многих единиц перевода, единственный разумный способ предоставить это объявление - поместить его в заголовочный файл и # включить его, когда это необходимо.

Когда вы создаете указатель на экземпляр (или ссылку), компилятору не нужно знать размер этого класса, поскольку указатель обычно имеет тот же размер 4 или 8 байтов. Для этих случаев вы можете просто использовать форвардное объявление вместо #include заголовка.

Теперь причина, по которой вы можете включить код в файл заголовка, связана с текущим шаблоном шаблонов C++. Этот код будет скомпилирован много раз, но компилятор/компоновщик исключит все копии и сохранит один в конечном компилированном коде.

Смежные вопросы