Почему NULL преобразуется в строку *? - PullRequest
4 голосов
/ 21 октября 2010

Я видел следующий код:

class NullClass {
public:
    template<class T> operator T*() const { return 0; }
};

const NullClass NULL;

void f(int x);
void f(string *p);

f(NULL); // converts NULL to string*, then calls f(string*)

Q1> У меня проблемы с пониманием следующего утверждения

template<class T> operator T*() const { return 0; }

Специально, что означает operator T*()?

Q2> Почему f(NULL) наконец вызывает f(string*)?

Спасибо

Ответы [ 6 ]

11 голосов
/ 21 октября 2010

что означает operator T*()?

Это пользовательский оператор преобразования.Он позволяет преобразовать объект типа NullClass в любой тип указателя.

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

Почему f(NULL) наконец вызывает f(string*)?

NULL имеет тип NullClass.Его нельзя преобразовать в int, но пользовательское преобразование NullClass -> T* можно использовать для его преобразования в string*, поэтому выбран void f(string*).

Обратите внимание, что это работаетпотому что есть только одна перегрузка f, которая принимает указатель.Если бы у вас было две перегрузки,

void f(int*);
void f(float*);

, вызов был бы неоднозначным, поскольку преобразование NullClass -> T* можно преобразовать как в int*, так и в float*.

2 голосов
/ 21 октября 2010

Q1> У меня проблемы с пониманием следующего утверждения

template<class T> operator T*() const { return 0; }

Специально, что означает operator T*()?

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

Q2> Почему f (NULL) наконец вызывает f (строку *)?

см. Выше. Преобразование в int невозможно, поэтому оператор неявного преобразования запускает и преобразует объект NullClass в любой запрошенный указатель.
Я предполагаю, что это предназначено. Обычно вы не хотите, чтобы указатель был преобразован в целое число, поэтому этот класс имеет неявное преобразование в любой указатель, но не в int.


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

2 голосов
/ 21 октября 2010
  1. operator Anything() перегружает оператор «cast». Всякий раз, когда NullClass необходимо преобразовать в Anything, будет вызвана эта функция и будет использован результат.

    В вашем случае Anything - это T*, где T может быть любого типа (это параметр шаблона), то есть NullClass поддерживает приведение к любым указателям.

  2. Поскольку NullClass может быть приведен к любым указателям, включая string*. Так что будет использоваться версия f(string*).

2 голосов
/ 21 октября 2010

template<class T> operator T*() означает, что существует неявное преобразование из NullClass в T* для любого T.

Когда вы вызываете f(NULL), компилятор должен решить, какую перегрузкуиспользовать.Поскольку ни одна из перегрузок не принимает объект типа NullClass, он просматривает, какие неявные преобразования существуют.Нет преобразования в int, но есть преобразование в string*, поэтому преобразование применяется и вызывается перегрузка string*.

1 голос
/ 21 октября 2010

Специально, что означает operator T*()?

Это оператор преобразования в тип T*. Это позволяет такие операции, как (T*)NULL.

Q2> Почему f (NULL) наконец вызывает f (строку *)?

Поскольку компилятор ищет лучшее соответствие между аргументами и сигнатурой метода, в этом случае выбираем template<typename T> NullClass::operator T*(), где T=string.

1 голос
/ 21 октября 2010

NuLLClass предоставляет функцию преобразования для преобразования в указатель. Когда вы вызываете f(NULL), он попытается найти способ преобразовать NULL в действительный аргумент для f.

Поскольку вы можете вызвать operator T*() в NULL, это будет с T = string. Это удовлетворяет спрос на f(string *). Поскольку нет способа преобразовать NULL в int, существует только один четкий выбор, какую функцию вызывать.

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