Передача аргумента в функцию - PullRequest
4 голосов
/ 15 февраля 2011

Это плохой принцип программирования - передавать arg в функцию, которая не является типом "точного соответствия", но имеет тривиальное или определяемое пользователем преобразование в этот тип? Например:

void f(bool option);

и позже в основном (это очень гипотетически, поэтому, пожалуйста, не советуйте с этим кодом):

int a = getSomeValue();

f(a);//here instead of bool I'm passing int - is it a bad programming practice or not?

Ответы [ 6 ]

6 голосов
/ 15 февраля 2011

Преобразование в bool является особым случаем, потому что оно не ведет себя как целочисленные преобразования, поэтому многим людям нравится видеть это явным, и это делается с помощью != 0, а не приведения.

Если вы передаете int в функцию, которая принимает long, то я, конечно, не хотел бы видеть это загроможденным каким-либо явным преобразованием.Точно так же я не хотел бы видеть char* приведение к const char*, чтобы передать его strlen.Эти преобразования «на самом деле ничего не делают»: они всегда сохраняют значение ввода, и в случае указателя это не позволяет вам делать что-либо с референтом, что вы не могли сделать с использованием исходного указателя.

Если вы передаете unsigned long функции, которая принимает unsigned int, то в некоторых реализациях (но далеко не во всех распространенных) это «сужающее преобразование», которое в зависимости от значений можетотбросить информацию, взяв модуль.В таких случаях часто рекомендуется сделать явное преобразование, чтобы случайный читатель не проверял сигнатуру функции, чтобы понять, что это происходит.Эти преобразования «делают что-то», что может быть удивительным.

То же самое происходит при преобразовании между целочисленным и плавающим типами: хотя int -> double безвреден практически для любой реализации, которую вы когда-либо увидите, double -> int не определенповедение для некоторых значений, поэтому вы не хотите, чтобы читатель пропустил его.

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

Например, если Foo имеет неявный конструктор, который принимает std::string, а некоторая функция bar принимает Foo, это не сильно отличается от POV вызывающего абонента bar, чем если бы API предоставил только явное преобразование, но две перегрузки bar, одна из которых принимает Foo, а другая - std::string, нопреобразует его прямо в Foo и вызывает другого.Поэтому полагаться на преобразование в таком случае не хуже, чем перегружать функцию.Последнее не считается преступлением века.За исключением программистов на Python.

6 голосов
/ 15 февраля 2011

Я думаю, что большинство людей сочтут эту плохую практику.Написание f(a !=0) гораздо яснее и кратко выражает намерение.

2 голосов
/ 15 февраля 2011

Да, я думаю, что это плохая практика программирования.

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

void doSomething (ClassX x, ClassY y, bool b);

Эта функция была вызвана с кодом, подобным этому:

ClassX x;
ClassY y;
doSomething (x, y, true);

Позже кто-то решил, что аргументы doSomething должны быть изменены, поскольку doSomething теперь также требует экземпляр ClassZ. Кроме того, логический аргумент был истинным во многих случаях, поэтому он был заменен на аргумент по умолчанию, например:

void doSomething (ClassX x, ClassY y, ClassZ z, bool b=true);

Хотя большая часть кода была изменена, показанный ранее вызов не изменился. Как ни странно, в ClassZ был неявный конструктор, принимающий в качестве аргумента значение bool:

class ClassZ
   {
   public:
      ClassZ(bool b);
   };

Произошло следующее. Этот звонок:

ClassX x;
ClassY y;
doSomething (x, y, true);

был тихо преобразован в это компилятором:

ClassX x;
ClassY y;
doSomething (x, y, ClassZ(true), true);

С 4-м аргументом по умолчанию true.

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

Таким образом:

  • никогда не полагаться на неявные преобразования
  • пометить конструкторы с 1 аргументом как явные
  • стараться избегать использования аргументов по умолчанию
1 голос
/ 15 февраля 2011

Все зависит от контекста.

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

Но есть и другие ситуации, в которых неявное преобразование в порядке:

std::ifstream f("File");
if (f) 
{
    // Testing f is relatively standard.
}

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

long theDistanceToLodond = getDistance("ToLondon");
InsideM25Action(static_cast<short>(theDistanceToLondon)); // All distances inside the M25 fit in a short therefore no information loss.

Но приведениям, когда никакая информация не потеряна, не должно быть явного приведения (это переполняет код, не предоставляя никакой выгоды) .Я не ожидал бы явного приведения указателей вниз к базовому классу и т. Д.

1 голос
/ 15 февраля 2011

Если вы передадите переменную short в f(int), тогда все в порядке.Но обратное опасно (т. Е. От int до short - возможное переполнение! ), и большинство компиляторов не будут рады и будут предупреждать вас.1009 *, так что да, намерение становится более ясным, когда вы пишете f(a!=0) при вызове f.Здесь мы делаем это для удобства чтения, а не для того, чтобы просто передать a как f(a).

0 голосов
/ 15 февраля 2011

Поскольку вы используете C ++, вы должны были сделать:

   int a = getSomeValue();
   f(static_cast<bool>(a));

Это, безусловно, будет выражать ваши намерения, поэтому у нас есть много типов явных приведений.

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