it-swarm-ru.tech

Где поместить значение параметра по умолчанию в C ++?

Какое место для значения параметра по умолчанию? Просто в определении функции, или объявлении, или в обоих местах?

283
Thomson

Значения параметров по умолчанию должны появиться в объявлении, так как это единственное, что видит вызывающая сторона.

EDIT: Как отмечают другие, вы можете иметь аргумент в определении, но я бы посоветовал написать весь код, как если бы это не было правдой.

288
Marcelo Cantos

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

91
sharptooth

Самое полезное место находится в объявлении (.h), чтобы его увидели все пользователи.

Некоторые люди также любят добавлять значения по умолчанию в реализацию (как комментарий):

void foo(int x = 42,
         int y = 21);

void foo(int x /* = 42 */,
         int y /* = 21 */)
{
   ...
}

Однако это означает дублирование и добавит возможность не синхронизировать комментарий с кодом (что хуже, чем некомментированный код? Код с вводящими в заблуждение комментариями!).

77
6502

Хотя это "старый" поток, я все же хотел бы добавить следующее:

Я испытал следующий случай:

  • В заголовочном файле класса я имел
int SetI2cSlaveAddress( UCHAR addr, bool force );
  • В исходном файле этого класса я имел
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
   ...
}

Как можно видеть, я поместил значение по умолчанию параметра "force" в исходный файл класса, а не в заголовочный файл класса.

Затем я использовал эту функцию в производном классе следующим образом (производный класс публично унаследовал базовый класс):

SetI2cSlaveAddress( addr );

предполагая, что параметр "force" будет принимать значение "false" как "само собой разумеющееся".

Однако компилятор (, переведенный в режим c ++ 11 , пожаловался и выдал мне следующую ошибку компилятора:

/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
                 from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2

Но когда я добавил параметр по умолчанию в заголовок базового класса:

int SetI2cSlaveAddress( UCHAR addr, bool force = false );

и удалил его из исходного файла базового класса:

int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )

тогда компилятор был доволен, и весь код работал должным образом (я мог бы дать один или два параметра функции SetI2cSlaveAddress())!

Таким образом, не только для пользователя класса важно поместить значение параметра по умолчанию в заголовочный файл, а также компилировать и функционировать, что, по-видимому, необходимо!

37
GeertVc

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

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

13
Tony Delroy

объявление, как правило, наиболее "полезно", но это зависит от того, как вы хотите использовать класс.

оба не действительны.

10
justin

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

void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
    using namespace std;
    cout << nVal1 << << nVal2 << endl;
}
10
ice911

Еще один момент, о котором я не нашел ни одного упомянутого:

Если у вас есть виртуальный метод, каждое объявление может иметь свое значение по умолчанию!

От того, какой интерфейс вы вызываете, зависит, какое значение будет использовано.

Пример на ideone

struct iface
{
    virtual void test(int a = 0) { std::cout << a; }
};

struct impl : public iface
{
    virtual void test(int a = 5) override { std::cout << a; }
};

int main()
{
    impl d;
    d.test();
    iface* a = &d;
    a->test();
}

Он печатает 50

Я настоятельно не рекомендую вам использовать его таким образом

9
relaxxx

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

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

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

3
Pervez Alam

Добавляем еще один пункт. Объявления функций с аргументом по умолчанию должны быть упорядочены справа налево и сверху вниз.

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

//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error 
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK

int main() {
    function("Using only one Default Argument", false, true);
    function("Using Two Default Arguments", false);
    function("Using Three Default Arguments");
    return 0;
}

//definition
void function(char const *msg, bool three, bool two, bool one ) {
    std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}
3
SridharKritha