Объявление функции внутри или вне класса
Я разработчик JAVA, который пытается изучить С++, но я действительно не знаю, что лучше всего подходит для объявлений стандартных функций.
В классе:
class Clazz
{
public:
void Fun1()
{
//do something
}
}
Или снаружи:
class Clazz
{
public:
void Fun1();
}
Clazz::Fun1(){
// Do something
}
У меня такое чувство, что второе может быть менее читаемым...
Ответы
Ответ 1
C++ является объектно-ориентированным в том смысле, что он поддерживает объектно-ориентированную парадигму разработки программного обеспечения.
Однако, в отличие от Java, C++ не заставляет вас группировать определения функций по классам: стандартный способ объявления функции C++ - просто объявить функцию без какого-либо класса.
Если вместо этого вы говорите об объявлении/определении метода, то стандартным способом является помещение только объявления во включаемый файл (обычно называемый .h
или .hpp
), а определение - в отдельный файл реализации (обычно называемый .cpp
или .cxx
)., Я согласен, что это действительно несколько раздражает и требует некоторого дублирования, но именно так, как был разработан язык.
Для быстрых экспериментов и проектов с одним файлом все будет работать... но для более крупных проектов такое разделение практически необходимо.
Примечание. Даже если вы знаете Java, C++ - это совершенно другой язык... и язык, который нельзя выучить экспериментально. Причина в том, что это довольно сложный язык с множеством асимметрий и явно нелогичным выбором, и, самое главное, когда вы совершаете ошибку, в Java нет "ангелов ошибок времени выполнения", которые спасут вас, как в Java... но есть вместо этого " неопределенные демоны поведения ".
Единственный разумный способ узнать C++ - это читать... независимо от того, насколько вы умны, вы никак не можете угадать, что решил комитет (на самом деле, быть умным - иногда даже проблема, потому что правильный ответ нелогичен и является следствием). исторического наследия.)
Просто выберите хорошую книгу или две и прочитайте их от корки до корки.
Ответ 2
Первый определяет вашу функцию-член как встроенную функцию, а второй - нет. Определение функции в этом случае находится в самом заголовке.
Вторая реализация поместит определение функции в файл cpp.
Оба семантически различны, и это не просто вопрос стиля.
Ответ 3
Определение функции лучше вне класса. Таким образом, ваш код может оставаться в безопасности, если потребуется. Файл заголовка должен просто указывать объявления.
Предположим, кто-то хочет использовать ваш код, вы можете просто дать ему файл .h и файл .obj(полученный после компиляции) вашего класса. Он не нуждается в файле .cpp для использования вашего кода.
Таким образом, ваша реализация не будет видна кому-либо еще.
Ответ 4
Метод "Внутри класса" (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: "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.
Файл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.
Ответ 5
Функции членов могут быть определены в определении класса или отдельно с использованием оператора разрешения области,::. Определение функции-члена в определении класса объявляет функцию inline, даже если вы не используете спецификатор inline. Таким образом, вы можете определить функцию 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;
}
Здесь важна только то, что вам нужно будет использовать имя класса непосредственно перед:: operator. Функция-член будет вызываться с использованием точечного оператора (.) На объекте, где он будет обрабатывать данные, относящиеся к этому объекту, только следующим образом:
Box myBox;
myBox.getVolume();
(from: http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm)
, оба способа являются законными.
Я не эксперт, но я думаю, если вы ставите только одно определение класса в один файл, то это не имеет большого значения.
но если вы примените что-то вроде внутреннего класса или имеете множественное определение класса, второе будет трудно читать и поддерживать.
Ответ 6
Первый должен быть помещен в заголовочный файл (где объявляется объявление класса). Второй может быть где угодно: либо заголовок, либо, как правило, исходный файл. На практике вы можете поместить небольшие функции в объявление класса (которое объявляет их неявно встроенными, хотя это компилятор, который в конечном итоге решает, будут ли они включены или нет). Однако большинство функций имеют объявление в заголовке и реализацию в файле cpp, как в вашем втором примере. И нет, я не вижу причин, почему это было бы менее читаемо. Не говоря уже о том, что вы можете разделить реализацию для типа в нескольких файлах cpp.
Ответ 7
Функция, определенная внутри класса, по умолчанию рассматривается как встроенная функция.
Простая причина, по которой вы должны определять свою функцию снаружи:
Конструктор класса проверяет виртуальные функции и инициализирует виртуальный указатель, указывающий на правильную таблицу VTABLE или таблицу виртуальных методов, вызывает конструктор базового класса и инициализирует переменные текущего класса, поэтому он действительно выполняет некоторую работу.
Встроенные функции используются, когда функции не так сложны и позволяют избежать накладных расходов на вызов функции. (Накладные расходы включают в себя скачок и ветвь на аппаратном уровне.)
И, как описано выше, конструктор не так просто считать встроенным.