Объясните перегрузку потоков с помощью указателей и typedef - PullRequest
1 голос
/ 13 февраля 2012

В моих файлах .h / .cpp есть следующий код:

.h:

class Foo;
typedef Foo * pFoo;

class Foo {
public:
    char c;
};
std::ostream& operator<<(std::ostream &out, const Foo &f);
std::ostream& operator<<(std::ostream &out, const pFoo &f);

.cpp:

std::ostream& operator<<(std::ostream &out, const Foo &f) { out << f.c; return out; }
std::ostream& operator<<(std::ostream &out, const pFoo &f) { out << f->c; return out; }

На основной когдаЯ запускаю следующий код:

Foo f;
f.c = 'a';
std::cout << "As foo object:" << f << std::endl;
std::cout << "As foo pointer:" << &f << std::endl;

Я получаю вывод:

As foo object:a
As foo pointer:a

Но, если, например, я заменю свой typedef на:

#define pFoo Foo*

Вместо этого я получаю вывод:

As foo object:a
As foo pointer:0x7fff5fbff980

Я знаю, что вы не можете перегрузить операторы для встроенных типов.Действительно ли typedef создает новый тип, или это просто псевдоним для существующего типа?Ответ, кажется, заключается в том, что он создает новый тип.Я в основном ищу более глубокое объяснение различий в поведении.(Я не пытаюсь сделать это в рабочем коде.)

Ответы [ 2 ]

2 голосов
/ 13 февраля 2012

Действительно ли typedef создает новый тип, или это просто псевдоним для существующего типа?

typedef вводит псевдонимы или синонимы для типов.

Что здесь происходит, так это то, что когда вы используете typedef, const pFoo является const указателем на Foo.
Когда вы просто заменяете pFoo на Foo*, используя определение, аргумент функции равен const Foo*, который является указателем на const Foo.

Попробуйте следующие варианты в качестве типа параметра:

const Foo * &
Foo const * &
Foo * const &

Обратите внимание, что, поскольку вы всегда можете разыменовать указатели, не должно быть никакой необходимости во второй перегрузке:

Foo *p = &f;
std::cout << *p << std::endl; 
1 голос
/ 13 февраля 2012

Во втором случае нет operator << совпадения по перегрузке, поэтому используется стандартный для указателей.

Когда вы используете typedef Foo * pFoo;, вы псевдоним Foo* с pFoo. Тогда const pFoo будет означать const (pFoo *), то есть pFoo* const, постоянный указатель на Foo . Поскольку &f может соответствовать const pFoo*, используется ваша вторая перегрузка.

#define pFoo Foo * просто воспроизводит pFoo' with Foo *. As a rfesult const pFoo expands into const Foo *, _pointer to constant Foo. &f не делает этого, поэтому используется стандартная перегрузка для указателя.

...