Разрешение перегрузки при вызове с NULL в качестве аргумента

У меня есть два перегруженных конструктора:

Hello::Hello(std::string message)
{
}

Hello::Hello(int *number)
{
}

Любой из этих конструкторов может занять адрес памяти. Если бы я сделал Hello hi(NULL); тогда что будет называться?

Также, если вы могли бы объяснить правила, поскольку они касаются перегруженных объектов. Аналогично, если бы у меня был один конструктор, который долго занимал параметр (Object::Object(long x)) и еще одна перегрузка (Object::Object(SomeOtherObject o)), который принимает объект, который долгое время имел перегрузку (SomeOtherObject::SomeOtherObject(long x)). Тогда я звоню Object obj((long)5); гарантированно позвонить одному или другому?

3 ответа

Решение

Caling std::string конструктор потребует дополнительного неявного преобразования, поэтому int* является предпочтительным.

Для второго сценария предпочтительным является исходный конструктор. Зачем компилятору искать какой-либо из других конструкторов, когда он имеет идеальное совпадение? И опять же, он включает в себя неявное преобразование, которое хуже, чем идеальное совпадение с прямым long конструктор предоставляет.

То, что есть конструктор, совершенно не имеет отношения к вашему примеру. Это просто разрешение перегрузки, и вы можете проверить это с помощью двух функций:

void foo(std::string s) {
}

void foo(int* n) {
}

призвание foo(NULL) приведет к звонку foo(int*), NULL является константой нулевого указателя и может быть неявно преобразована в каждый тип указателя, и наилучшим преобразованием в этом контексте является int*, Другая перегрузка потребует двух преобразований, что оценивается хуже.

Второй сценарий довольно очевиден: идеальное совпадение предпочтительнее.

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

Когда у вас есть конструктор класса с одним объектом, как ваш Object(SomeOtherObject o) по стилю лучше пометить этот конструктор словом explicit, поэтому компилятор не будет пытаться делать неявные преобразования. Например, учитывая определения:

class A {
  A(int x);
};

class B {
  explicit B(A a);
};

пытаясь создать объект, как B b(100) будет ошибка компиляции.

См. Также раздел " Руководство по стилю Google C++" по этой теме.

Другие вопросы по тегам