Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Привет всем.
КД>Что-то я немного недоумеваю со следующего кода, который без проблем скомпилировался в VS2010 и VS2012.
КД>
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>На мой мутный взгляд — компилятор пропустил багу. Он же должен ругаться что TAccessor::get_check не реализован?
В смысле что попытка создать экземпляр абстрактного класса + override несуществующего метода базовового класса, ты хотел сказать?..
А почему, собственно?
Вообще-то в С++ перегрузка методов по типу возвращаемого значения допускается только для пользовательстких операторов преобразования к типу...
То есть всё что могло бы быть, так это запрет возвращать из TObject::get_check неконстантную ссылку. То есть ругаться должен был бы, на то, что тип возвращаемого значения в реализации не совпадает с типов возвращаемого значения в базе...
но тут есть такая штука, как ковариантность виртуальных функций, что ли, оно называется.
Ты можешь сделать так примерно:
struct Base {
virtual ~Base() {}
Base* Clone() const { return new Base( *this ); }
};
struct Der : Base {
Der* Clone() const { return new Der( *this ); }
};
и всё при этом получится, потому, что С++ позволяет в виртуальном методе наследника заменять тип результата на совместимый...
КД>Или я чего-то не понимаю?
Я так думаю, что у тебя тот же случай, но боюсь, что это нестандарьтное расширение от MS, хотя и не уверен...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
КД>>На мой мутный взгляд — компилятор пропустил багу. Он же должен ругаться что TAccessor::get_check не реализован?
E>А почему, собственно?
Я думаю, компилятор не должен игнорировать потерю константности у возвращаемого типа.
E>но тут есть такая штука, как ковариантность виртуальных функций, что ли, оно называется.
Про это я знаю. И даже эксплуатирую. И ругался что похожего нет в C#
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Я думаю, компилятор не должен игнорировать потерю константности у возвращаемого типа.
Так у этой функции сигнатура та же, другое только возвращаемое значение...
попробуй поменять в наследнике именно сигнатуру, например константность самого метода, и посмотри на что и как будет ругаться
КД>Здесь, я думаю, ситуация другая.
Почему? попробуй в наследнике вернуть int, например...
только можно попроще код-то замутить...
struct Base { virtual const Base* This() { return this; } };
struct Der : Base { Base* This() override { return this; } } testObj;
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>но тут есть такая штука, как ковариантность виртуальных функций, что ли, оно называется. E>Я так думаю, что у тебя тот же случай, но боюсь, что это нестандарьтное расширение от MS, хотя и не уверен...
Штука эта называется ковариантностью возвращаемых типов. В стандарте (как в старом, так и в новом) она прописана в п.10.3 и разрешена только для классов:
The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:
— both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes
— the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
— both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.
И похоже, расширение для этой фичи для встроенных типов сделано не только в msvc: http://ideone.com/MNzqzi
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Erop, Вы писали:
E>Так у этой функции сигнатура та же, другое только возвращаемое значение... E>попробуй поменять в наследнике именно сигнатуру, например константность самого метода, и посмотри на что и как будет ругаться
Ошибка 1 error C3668: TObject::get_check: метод со спецификатором переопределения "override" не переопределяет какие-либо методы базового класса D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 25
Ошибка 2 error C2259: TObject: невозможно создать экземпляр абстрактного класса D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 38
КД>>Здесь, я думаю, ситуация другая. E>Почему? попробуй в наследнике вернуть int, например...
Ошибка 1 error C2555: TObject::get_check: возвращаемый тип перегруженной виртуальной функции отличается от "TAccessor::get_check" и не является ковариантным D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 26
Ошибка 2 error C2556: TCheck *TObject::get_check(void) const: перегруженная функция отличается от "int *TObject::get_check(void) const" только возвращаемым типом D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 30
Ошибка 3 error C2371: TObject::get_check: переопределение; различные базовые типы D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 30
Что первая, что вторая ошибка — это нормальное положение вещей.
E>только можно попроще код-то замутить... E>
struct Base { virtual const Base* This() { return this; } };
E>struct Der : Base { Base* This() override { return this; } } testObj;
Возможно. Я просто воспроизвел хоровод классов из реального проекта.
Удивительно, что я вообще это заметил. После перехода на VC я конкретно расслабился в отношении таких вещей. Но, видать, сапёр во мне еще не умер
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
R>— both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.
R>И похоже, расширение для этой фичи для встроенных типов сделано не только в msvc: http://ideone.com/MNzqzi
Дык у ТС всё по стандарту жеж...
только понятие less cv-qualification довольно мутное, но в данном случае оно наверное же less?
А то, что можно не только классы, но и на разное удругое указатели ковариантить, так это да, вроде все умеют, благо бесплатно жеж...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
КД>Ошибка 1 error C3668: TObject::get_check: метод со спецификатором переопределения "override" не переопределяет какие-либо методы базового класса D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 25
КД>Ошибка 2 error C2259: TObject: невозможно создать экземпляр абстрактного класса D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 38
Бинго! А я что говорил?..
E>>Почему? попробуй в наследнике вернуть int, например... КД>
КД>Ошибка 1 error C2555: TObject::get_check: возвращаемый тип перегруженной виртуальной функции отличается от "TAccessor::get_check" и не является ковариантным D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 26
КД>Что первая, что вторая ошибка — это нормальное положение вещей.
Ну так у тебя тип ковариантный, вот и вся недолга...
КД>Возможно. Я просто воспроизвел хоровод классов из реального проекта.
Ну чем проще пример, тем проще понять, даже и самом в том числе
КД>Удивительно, что я вообще это заметил. После перехода на VC я конкретно расслабился в отношении таких вещей. Но, видать, сапёр во мне еще не умер
Дык это совершенно стандартное поведение. Если бы ты хотя бы указатель на встроенный тип возращал, что ли, а так всё просто тупо по станадарту...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Ошибка 1 error C2555: TObject::get_check: возвращаемый тип перегруженной виртуальной функции отличается от "TAccessor::get_check" и не является ковариантным D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 26
Ошибка 2 error C2556: TCheck *TObject::get_check(void) const: перегруженная функция отличается от "const TCheck *TObject::get_check(void) const" только возвращаемым типом D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 30
Ошибка 3 error C2373: TObject::get_check: переопределение; различные модификаторы типа D:\Users\Dima\Work\TestCode\compiler_test\test_015\source\main.cpp 30
Вообщем, я думаю, компилятор и в первом случае должен был возбудиться
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, rg45, Вы писали:
R>Штука эта называется ковариантностью возвращаемых типов. В стандарте (как в старом, так и в новом) она прописана в п.10.3 и разрешена только для классов:
Точно! +100500, никогда не мог запомнить это бредовое название.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Коваленко Дмитрий, Вы писали:
E>>только можно попроще код-то замутить... E>>
struct Base { virtual const Base* This() { return this; } };
E>>struct Der : Base { Base* This() override { return this; } } testObj;
КД>Возможно. Я просто воспроизвел хоровод классов из реального проекта.
КД>Удивительно, что я вообще это заметил. После перехода на VC я конкретно расслабился в отношении таких вещей. Но, видать, сапёр во мне еще не умер
А что, как по мне, это достаточно разумное и удобное решение. Типовая безопасность от этого не страдает — при обращении к объекту через указатель или ссылку на базу константность не снимается, а наоборот, добавляется. А вот если попытаться сделать наоборот (перенести модификатор const из базового класса в производный), тогда уже возникнет угроза непреднамеренного снятия константности, и в этом случае компилятор уже должен выдать ошибку.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Вообщем, я думаю, компилятор и в первом случае должен был возбудиться
Нет, не должен!
В ковариантности возвращаемого значения виртуальной функции то, что результат наследника должен приводиться к результату предка -- ключевое.
Код, который работает с указателем на прпедка должен же как-то мочь работать?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Вообщем, я думаю, компилятор и в первом случае должен был возбудиться
Хотя, если принять во внимание, что указателю на "неконстантное" можно присваивать указатель на "константное", а наоборот нельзя — то получается, что компилятор ведет себя вполне логично.
Ладно, век живи век учись.
Всем спасибо за проявленный интерес
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>>Вообщем, я думаю, компилятор и в первом случае должен был возбудиться
КД>Хотя, если принять во внимание, что указателю на "неконстантное" можно присваивать указатель на "константное", а наоборот нельзя — то получается, что компилятор ведет себя вполне логично.
Здравствуйте, Mr.Delphist, Вы писали:
КД>>>Вообщем, я думаю, компилятор и в первом случае должен был возбудиться
КД>>Хотя, если принять во внимание, что указателю на "неконстантное" можно присваивать указатель на "константное", а наоборот нельзя — то получается, что компилятор ведет себя вполне логично.
MD>Я бы на его месте таки бросал ворнинг...
Да не. С точки зрения компилятора — здесь (действительно) все чисто.
Я (сейчас) даже не уверен, что такое имеет смысл отслеживать на уровне статического (или как он там называется) анализа кода...
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Erop, Вы писали:
R>>Штука эта называется ковариантностью возвращаемых типов. В стандарте (как в старом, так и в новом) она прописана в п.10.3 и разрешена только для классов: E>Точно! +100500, никогда не мог запомнить это бредовое название.
Здравствуйте, Erop, Вы писали:
E>но тут есть такая штука, как ковариантность виртуальных функций, что ли, оно называется.
E>Ты можешь сделать так примерно:
struct Base {
E> virtual ~Base() {}
E> Base* Clone() const { return new Base( *this ); }
E>};
E>struct Der : Base {
E> Der* Clone() const { return new Der( *this ); }
E>};
E>
и всё при этом получится, потому, что С++ позволяет в виртуальном методе наследника заменять тип результата на совместимый...
Конечно облом. Как ты себе представляешь реализацию такой виртуальности?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском