2012-01-31 2 views
60

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

В классе:

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

Или снаружи:

class Clazz 
{ 
public: 
    void Fun1(); 
} 

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

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

+5

Возможно, книга новичка на C++ может быть в порядке? –

+28

@ Разборщики почему? что не так с моим вопросом? – JohnJohnGa

+0

На самом деле есть 3 варианта. Второй пример может содержать определение функции в файле заголовка (но все еще не вложенное) или в отдельный файл '.cpp'. –

ответ

13

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

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

Оба семантически отличаются друг от друга, и это не просто вопрос стиля.

+1

http://www.cplusplus.com/doc/tutorial/classes/ дает тот же ответ: «Единственное различие между определением функции члена класса полностью внутри его класса или включением только прототипа, а затем его определения, заключается в том, что в в первом случае функция автоматически будет считаться встроенной функцией-членом компилятором, а во втором она будет нормальной (не-встроенной) функцией-членом класса, которая на самом деле не предполагает никакой разницы в поведении ». – Buttons840

2

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

37

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

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

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

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

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

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

Просто выберите good book или два и прочитайте их на обложке.

+4

Если кто-то приходит из Java и просит о помощи на C++, то что он говорит ему, если вы говорите «язык, о котором вы знаете, одержим чем-то»? У него нет сравнения с другими языками, поэтому это почти ничего не говорит. Лучше, чем использовать сильное эмоционально-условное слово, подобное одержимому, которое не очень сильно говорит OP, вы можете просто оставить эту часть. Более того, каков контекст «использовать класс для каждого»? В Java вы не используете класс для метода. Вы не используете класс для переменной. Вы не используете класс для файла. Итак, что здесь «все»? Разглагольствование? –

+1

@ DanielS: Убрана эта часть, потому что, видимо, оскорбляла вас (не знаю почему). Конечно, я не пишу о Java, потому что я вообще не использую Java, я просто подумал, что OOP в качестве Object Obsessed Programming был забавной шуткой, хотя, по-видимому, это не так. Я был сертифицированным Java 1.1 программистом, но тогда решил, что, если только не будет принужден по какой-то причине, я не буду использовать этот «язык программирования», и до сих пор мне удалось его избежать. – 6502

+0

Спасибо, я думаю, что сейчас он читается намного лучше. Извините, если я обижусь. В следующий раз я постараюсь быть более позитивным. –

12

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

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

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

8

Метод «Внутри класса» (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... 
} 

file3: "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. 

Файл4: "AlsoUseClazz.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. 

file5: "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

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

class Box 
{ 
    public: 

    double length; 
    double breadth;  
    double height;  

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

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

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

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

Box myBox;   

myBox.getVolume(); 

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

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

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

+0

Можете ли вы привести соответствующий контент из этой ссылки в тело своего сообщения и, таким образом, будущие проверки против мертвых ссылок? благодаря – JustinJDavies

1

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

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

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

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