Объявление функции внутри или вне класса - PullRequest
79 голосов
/ 31 января 2012

Я - разработчик JAVA, который пытается изучать C ++, но я не знаю, как лучше всего применять стандартные объявления функций.

В классе:

class Clazz
{
 public:
    void Fun1()
    {
        //do something
    }
}

Или снаружи:

class Clazz
{
public:
    void Fun1();
}

Clazz::Fun1(){
    // Do something
}

У меня такое ощущение, что второй может быть менее читабельным ...

Ответы [ 7 ]

48 голосов
/ 31 января 2012

C ++ является объектно-ориентированным в том смысле, что он поддерживает объектно-ориентированную парадигму разработки программного обеспечения.

Однако, в отличие от Java, C ++ не заставляет вас группировать определения функций в классах: стандартный C ++способ объявления функции - просто объявить функцию без какого-либо класса.

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

Для быстрых экспериментов и проектов с одним файлом все будет работать ... но для более крупных проектов такое разделение является тем, что практически требуется.

Примечание. Даже если вы знаете Java, C ++ - это совершенно другой язык ... и он не может быть изучен экспериментальным путем.Причина в том, что это довольно сложный язык с множеством асимметрий и, по-видимому, нелогичным выбором, и, самое главное, когда вы совершаете ошибку, в Java нет «ангелов ошибок времени выполнения», которые спасут вас, как в Java ... но есть вместо этого »undefined поведенческие демоны ".

Единственный разумный способ выучить C ++ - это читать ... независимо от того, насколько вы умны, нет никакого способа угадать, что решил комитет (на самом деле, быть умным - иногда даже проблемапотому что правильный ответ нелогичен и является следствием исторического наследия.)

Просто выберите хорошую книгу или две и прочитайте их от корки до корки.

20 голосов
/ 31 января 2012

Первая определяет вашу функцию-член как встроенную функцию , а вторая - нет.Определение функции в этом случае находится в самом заголовке.

Вторая реализация поместит определение функции в файл cpp.

Оба семантически различны, и это не просто вопрос стиля.

15 голосов
/ 31 января 2012

Определение функций лучше вне класса.Таким образом, ваш код может оставаться безопасным, если потребуется.Файл заголовка должен просто давать объявления.

Предположим, что кто-то хочет использовать ваш код, вы можете просто дать ему файл .h и файл .obj (полученный после компиляции) вашего класса.Ему не нужен файл .cpp для использования вашего кода.

Таким образом, ваша реализация не видна никому другому.

10 голосов
/ 14 октября 2013

Метод «Внутри класса» (I) делает то же самое, что и метод «вне класса» (O).

Однако (I) можно использовать, когда класс используется только в одном файле (внутри файла .cpp).(O) используется, когда он находится в заголовочном файле.Файлы cpp всегда компилируются.Заголовочные файлы компилируются, когда вы используете #include "header.h".

Если вы используете (I) в заголовочном файле, функция (Fun1) будет объявляться каждый раз, когда вы включаете #include "header.h».Это может привести к объявлению одной и той же функции несколько раз.Это сложнее для компиляции, и может даже привести к ошибкам.

Пример правильного использования:

Файл1: "Clazz.h"

//This file sets up the class with a prototype body. 

class Clazz
{
public:
    void Fun1();//This is a Fun1 Prototype. 
};

Файл2: "Clazz.cpp"

#include "Clazz.h" 
//this file gives Fun1() (prototyped in the header) a body once.

void Clazz::Fun1()
{
    //Do stuff...
}

Файл3: "UseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz;
MyClazz.Fun1();//This does Fun1, as prototyped in the header.

File4: "ТакжеUseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz2;
MyClazz2.Fun1();//This does Fun1, as prototyped in the header. 

Файл5: "DoNotUseClazzHeader.cpp"

//here we do not include Clazz.h. So this is another scope. 
class Clazz
{
public:
    void Fun1()
    {
         //Do something else...
    }
};

class MyClazz; //this is a totally different thing. 
MyClazz.Fun1(); //this does something else. 
3 голосов
/ 10 сентября 2014

Функции-члены могут быть определены в определении класса или отдельно с помощью оператора разрешения области видимости ::.Определение функции-члена в определении класса объявляет функцию встроенной, даже если вы не используете встроенный спецификатор.Таким образом, вы можете определить функцию Volume (), как показано ниже:

class Box
{
  public:

     double length;
     double breadth;    
     double height;     

     double getVolume(void)
     {
        return length * breadth * height;
     }
};

Если хотите, вы можете определить ту же функцию вне класса с помощью оператора разрешения области видимости: :: следующим образом

double Box::getVolume(void)
{
   return length * breadth * height;
}

Здесь единственный важный момент заключается в том, что вам придется использовать имя класса непосредственно перед оператором ::.Функция-член будет вызываться с использованием точечного оператора (.) Для объекта, где она будет манипулировать данными, связанными с этим объектом, только следующим образом:

Box myBox;           

myBox.getVolume();  

(из: http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm), в обе стороныявляются законными.

Я не эксперт, но я думаю, что если вы поместите только одно определение класса в один файл, то это не имеет значения.

, но если вы примените что-то вродевнутренний класс, или у вас есть определение нескольких классов, второе будет трудно читать и поддерживать.

2 голосов
/ 31 января 2012

Первый должен быть помещен в заголовочный файл (где находится объявление класса).Второй может быть где угодно, либо в заголовке, либо, обычно, в исходном файле.На практике вы можете поместить небольшие функции в объявление класса (которое объявляет их неявно встроенными, хотя компилятор в конечном итоге решает, будут ли они встроены или нет).Однако большинство функций имеют объявление в заголовке и реализацию в файле cpp, как во втором примере.И нет, я не вижу причин, почему это было бы менее читабельным.Не говоря уже о том, что вы могли бы на самом деле разделить реализацию для типа по нескольким файлам cpp.

1 голос
/ 05 октября 2016

Функция, определенная внутри класса, по умолчанию рассматривается как встроенная функция. Простая причина, почему вы должны определить свою функцию снаружи:

Конструктор класса проверяет наличие виртуальных функций и инициализирует виртуальный указатель для указания на правильный VTABLE или таблицу виртуальных методов , вызывает конструктор базового класса и инициализирует переменные текущего класса, поэтому это на самом деле делает некоторую работу.

Встроенные функции используются, когда функции не так сложны и позволяют избежать издержек при вызове функции. (Накладные расходы включают скачок и переход на аппаратном уровне.) И, как описано выше, конструктор не так прост, чтобы считаться встроенным.

...