LINUX.ORG.RU

Александреску, C☩☩, неявное преобразование типов.


0

0

Читая Александреску обратил снимание что он приводит пример
 (аналогичный тому что ниже) и утверждает что будет вызвано
void testFunc(const Test &t) , однако у меня вызывается 
void testFunc(double i), если ее убрать то да видны все достоинства 
неявного преобразования типов. Вопрос шо за компилятор использует александреску?

#include "stdio.h"

class Test{
public:
    /*explicit*/ Test(unsigned int i){
    }
};

void testFunc(double i){
    printf("Call i\n");
}

void testFunc(const Test &t){
    printf("Call t\n");
}

int main()
{
    int b = 0;
    testFunc(b);
}
★★☆
Ответ на: комментарий от JackYF

>> А если шаблонную функцию поместить перед нешаблонной?

Где ты в примере выше нашёл шаблонную функцию? =)

Deleted
()
Ответ на: комментарий от wfrr

> Осталось найти эту книгу.

Да, это многое объясняет.

В приведенном тобой примере вызов функции разрешается встроенным преобразованием int -> double, так что конструктор Test(unsigned int i) даже не рассмартивается.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Да, это многое объясняет.

Тем не менее вы меня не поняли, искать нужно книгу где написан
 компилятор. А оригинальный пример вот:
----
Пример 1. Перегрузка. Пусть у нас есть, например, Widget::Widget(unsigned int),
 который может быть вызван неявно, и функция Display, перегруженная
 для Widget и double. Рассмотрим следующий сюрприз при разрешении
 перегрузки:
  
void Display(double); // Вывод double
void Display(const Widget&); // Вывод Widget
Display(5); // Гм! Создание и вывод Widget
----

Вот ссылка: http://64.233.183.104/search?q=cache:HacoGLIY7RIJ:www.williamspublishing.com/PD
F/5-8459-0859-0/part.pdf

страница 85

>В приведенном тобой примере вызов функции разрешается встроенным
 преобразованием int -> double, так что конструктор Test(unsigned
 int i) даже не рассмартивается.

Расскажите это автору книги.

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

> Тем не менее вы меня не поняли

Выражайся яснее.

>>В приведенном тобой примере вызов функции разрешается встроенным преобразованием int -> double, так что конструктор Test(unsigned int i) даже не рассмартивается.

>Расскажите это автору книги.

Встречу - расскажу обязательно.

tailgunner ★★★★★
()
Ответ на: комментарий от Deleted

Упс. Разул глаза. Забейте на моё сообщение :)

JackYF ★★★★
()
Ответ на: комментарий от tailgunner

Ага, но всетаки насчет компилятора который у александреску выдает такие кренделя вы не рассказали.

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

> Ага, но всетаки насчет компилятора который у александреску выдает такие кренделя вы не рассказали.

Кто тебе сказал, что фрагмент со страницы 85 вообще проверялся компилятором? Там же проверять нечего.

В "Modern C++ design" (?) Александреску пользовался Comeau и MSVC (версий не помню, давно читал).

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Кто тебе сказал, что фрагмент со страницы 85 вообще проверялся компилятором? Там же проверять нечего.

Тогда на чем основано утверждение аленксандреску что вызовется "void Display(const Widget&)" если по логике оно там вызываться не должно?

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

> Тогда на чем основано утверждение аленксандреску что вызовется "void Display(const Widget&)"

Не знаю. Возможно, на каком-то старом стандарте или компиляторе. Или он просто ошибся.

Есть у тебя знакомы вендузятнеги с MSVC? Попроси их прогнать твой код 8)

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Прогнал под MVCExpress 8 , такая же фигня.

wfrr ★★☆
() автор топика

void f(char *a)
{
	printf("char* %d", *a);
}

void f(int a)
{
	printf("int %d", a);
}

int main(int argc, char* argv[])
{
	f(NULL);
	getc(stdin);
	return 0;
}

Что выведет этот недоязык? ;)

anonymous
()
Ответ на: комментарий от anonymous

>Ну вот, а теперь подумай головой и пойми, что это отстой.

Хм, попробовал подумать... Еще попробовал... Не получается... Почему же отстой?

anonymous
()
Ответ на: комментарий от tailgunner

>> Почему же отстой?

>Потому что так сказал анонимус. Ты что, не веришь всезнающему >анонимусу? O_o

Верю... Я б сказал, как самому себе))

anonymous
()
Ответ на: комментарий от anonymous

Да потому что в С++ все через жопу. И NULL тоже сделали не в виде (void*)0, как в Си, а как обычный 0, и все из-за того, что в С++ есть о$%#ть какое гениальное правило: указатель void * надо обязательно приводить к др. типу, хотя смысла в этом приведении вообще нет никакого, просто маразм на пустом месте. Поэтому нормальный NULL равный (void*)0 пришлось бы всегда приводить, например (char*) NULL. Я удивляюсь, почему великий Страуструп так не сделал! Он же любит подобные "штучки". Однако он предпочел просто 0, и я, написав NULL, получил не указатель, а ноль, и вызвал не ту ф-ию.

anonymous
()
Ответ на: комментарий от anonymous

> Да потому что в С++ все через жопу. И NULL тоже сделали не в виде (void*)0, как в Си, а как обычный 0, и все из-за того, что в С++ есть о$%#ть какое гениальное правило: указатель void * надо обязательно приводить к др. типу, хотя смысла в этом приведении вообще нет никакого, просто маразм на пустом месте. Поэтому нормальный NULL равный (void*)0 пришлось бы всегда приводить, например (char*) NULL. Я удивляюсь, почему великий Страуструп так не сделал! Он же любит подобные "штучки". Однако он предпочел просто 0, и я, написав NULL, получил не указатель, а ноль, и вызвал не ту ф-ию.

Для дебилов, обьясним: ВСЕ ПРОСТО, в C++, в отличии от C, есть более чем 1 оператор приведения типа, имеющие разную логику работы:

reinterpret_cast

static_cast

dynamic_cast

const_cast

и еще несколько, в нестандартизованных (ныне) расширениях. Ведут они себя различным образом, и если например 
reinterpret_cast больше всех похож на С-шное приведение типов, то например static_cast проверяет типобезопасность, 
на этапе компиляции, а dynamic_cast вообще позволяет в рантайме определить, можно ли обьект прикастить к этому типу, или нет.
Особняком стоит const_cast, он нужен для "разконстанчивания" константных обьектов, но это нужно исключительно как 
лекарство, нет, не от кривизны языка, а от кривизны быдла, не осилившего сразу написать правильный код.  Таким образом 
остается 3 приведения типа основных: 

reinterpret -- простое наложение новой структуры, по указанному адресу, без каких-либо проверов времени компиляции/выполнения

static -- с проверкой типобезопасности на этапе компиляции

dynamic -- с runtime проверкой приводимости обьекта к указанному типу

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

На последок, пример для тех, кто верит в (type*)obj:

$ cat 1.cpp

#include <stdio.h>

struct A { int a[10]; };
struct B { int b[0];  };
struct C : public A, B { };

int main()
{
        C obj;
        void *vpa = (void*)(A*)&obj;
        void *vpb = (void*)(B*)&obj;

        if (vpa != vpb)
        {
                printf("ptrdiff1=%d\n", (char*)vpb-(char*)vpa);
                printf("ptrdiff2=%d\n", (C*)vpb-(C*)vpa);
        }
}

$ ./1
ptrdiff1=40
ptrdiff2=1


anonymous
()
Ответ на: комментарий от anonymous

> Да потому что в С++ все через жопу. И NULL тоже сделали не в виде (void*)0, как в Си, а как обычный 0, и все из-за того, что в С++ есть о$%#ть какое гениальное правило: указатель void * надо обязательно приводить к др. типу, хотя смысла в этом приведении вообще нет никакого, просто маразм на пустом месте. Поэтому нормальный NULL равный (void*)0 пришлось бы всегда приводить, например (char*) NULL. Я удивляюсь, почему великий Страуструп так не сделал! Он же любит подобные "штучки". Однако он предпочел просто 0, и я, написав NULL, получил не указатель, а ноль, и вызвал не ту ф-ию.

Ксате, ваш гневный выпад, - вдоль: 

#include <stdio.h>
#include <stdlib.h>

struct A { int a; };

int main()
{
        A *a = new A;

        if (a == (void*)0)
        {
                printf("unreachable line reached!\n");
        }
}

ЧЯДНТ? Для совсем уродов поясню: при сравнении указателя с void* указателем, срабатывает 

operator void* 

имеющийся у всех "простых" указателей, позволяющий привести любой не-воид указатель к воиду, его компилятор и находит,
и далее уже и не делает попыток привести void к обьекту.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.