Название: Возможный баг в компиляторе MSVC 2013 Отправлено: Racheengel от Июль 13, 2017, 16:20 Всем привет...
Наткнулся на странную вещь, которую иначе как багом компилятора, объяснить трудно. Есть 2 интерфейса, IName и ITaskName. Оба имеют одинаковый метод GetName: Цитировать class IName{ public: virtual QString GetName() const = 0; } class ITaskName{ public: virtual QString GetName() const = 0; } Для IName существует имплементация CName: Код: class CName: virtual public IName{ И есть имплементация для ITaskName, которая отнаследована также от CName: Код: class CTask: virtual public CName, virtual public ITaskName Вроде бы все ок - проблема неоднозначности родителя решается через виртуальное наследование + конкретное указание наследованного метода через using . Однако компилятор упорно сообщает, что не может создать абстракный класс CTask. Решается эта проблема следующим костылем: Код: class CTask но в таком случае возникает вопрос - а что не так с using CName::GetName; ??? Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 17:03 Решается эта проблема следующим костылем: Мне кажется, что таким образом перегружается метод ITaskName::GetName, который в интерфейсе объявлен чистым виртуальным. Без объявления экземпляров класса CTask, вроде, должно всё скомпилироваться, а сам CTask будет являться абстрактным классом.Код: class CTask Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Авварон от Июль 13, 2017, 17:31 В гцц та же проблема. АФАИК, это не имеет ничего общего с виртуальным наследованием - оно призвано решать проблему ромбовидного наследования (а точнее, когда один и тот же базовый класс встречается в двух ветвях иерархии). Здесь же ситуация другая - есть разные классы (но с одноименными методами).
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 17:44 В gcc нет такой проблемы. пруф (https://ideone.com/yOImk6)
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Авварон от Июль 13, 2017, 17:55 В 4.8.4 есть:
Цитировать /usr/bin/g++ --version g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 /usr/bin/g++ -g -O0 -Wall -Wextra -m64 -pipe -fexceptions -fvisibility=default -fPIC -DQT_DEPRECATED_WARNINGS -DQT_CORE_LIB -I/home/abbapoh/Qt/5.9/gcc_64/include -I/home/abbapoh/Qt/5.9/gcc_64/include/QtCore -I/home/abbapoh/Qt/5.9/gcc_64/mkspecs/linux-g++ -I/home/abbapoh/programming/build-cpptest-Desktop_Qt_5_9_0_GCC_64bit-Debug/qtc_Desktop__baa544a4-debug/cpptest.qtc-Desktop--baa544a4.063e55c3/qt.headers -std=c++0x -o /home/abbapoh/programming/build-cpptest-Desktop_Qt_5_9_0_GCC_64bit-Debug/qtc_Desktop__baa544a4-debug/cpptest.qtc-Desktop--baa544a4.063e55c3/.obj/3a52ce780950d4d9/main.cpp.o -c /home/abbapoh/programming/cpptest/main.cpp /home/abbapoh/programming/cpptest/main.cpp: In function ‘void g()’: /home/abbapoh/programming/cpptest/main.cpp:43:8: warning: unused variable ‘dr’ [-Wunused-variable] D& dr = dynamic_cast<D&>(*bp); // fails ^ /home/abbapoh/programming/cpptest/main.cpp: In function ‘int main(int, char**)’: /home/abbapoh/programming/cpptest/main.cpp:75:11: error: cannot declare variable ‘t’ to be of abstract type ‘CTask’ CTask t; ^ /home/abbapoh/programming/cpptest/main.cpp:65:7: note: because the following virtual functions are pure within ‘CTask’: class CTask: virtual public CName, virtual public ITaskName ^ /home/abbapoh/programming/cpptest/main.cpp:57:17: note: virtual QString ITaskName::GetName() const virtual QString GetName() const = 0; ^ Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Авварон от Июль 13, 2017, 18:01 В gcc нет такой проблемы. пруф (https://ideone.com/yOImk6) Лол, ну вы бы хоть инстанс класса бы создали :D Проверил - gcc, clang и icc не хавают. Ни одна из версий. Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 18:04 Эта диагностика показывает о попытке создать экземпляр/разыменовать указатель на абстрактный класс
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 18:05 Более простым для восприятия кодом
Код
Цитировать prog.cpp: In function ‘int main()’: prog.cpp:13:9: error: cannot declare variable ‘t’ to be of abstract type ‘IPrint’ IPrint t; ^ prog.cpp:3:7: note: because the following virtual functions are pure within ‘IPrint’: class IPrint { ^~~~~~ prog.cpp:5:15: note: virtual void IPrint::print() virtual void print() = 0; ^~~~~ Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Авварон от Июль 13, 2017, 18:08 Ииии? У топикстартера именно эта проблема и есть:
Цитировать Однако компилятор упорно сообщает, что не может создать абстракный класс CTask. Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 18:11 В gcc нет такой проблемы. пруф (https://ideone.com/yOImk6) Класс создан (объявлен). Создать экземпляр абстрактного класса невозможно в соответствии со стандартом c++.Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Авварон от Июль 13, 2017, 18:19 Рукалицо.
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 18:20 Что не так?
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Igors от Июль 13, 2017, 18:22 Не понял
Код: class CTask: virtual public CName, virtual public ITaskName Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Racheengel от Июль 13, 2017, 19:09 ITaskName это интерфейс, "чисто абстрактный" класс.
Поэтому автоматом ничего и не создается - он служит только для предоставления доступа к перегруженным методам имплементаций. А CTask - это конкретная имплементация, которая наследована от базового CName, имеющего тот же метод, что и ITaskName, на уровне объявления интерфейса. Я так понимаю, что проблема в том, что базовые классы ITaskName и IName не имеют общего предка, объявляющего метод GetName. Но разве это не должно разруливаться на этапе линковки, т.к. оба метода на уровне интерфейсов - абстрактны? Тем более CName уже помещает в виртуальную таблицу свой CName::GetName, не понятно, почему линкер не может связать ITaskName::GetName с CName::GetName по одинаковым сигнатурам. Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: __Heaven__ от Июль 13, 2017, 21:22 Racheengel, дело в том, что CTask содержит не одну виртуальную таблицу, а две, в каждой из которой имеется адрес на метод GetName и адреса напротив них записываются разные.
Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Igors от Июль 14, 2017, 09:34 не понятно, почему линкер не может связать ITaskName::GetName с CName::GetName по одинаковым сигнатурам. Линкер тут ни при чем. Допустим Вы написали Код Ожидается что test - наследник абстрактного ITaskName, т.е. поведение его виртуальных методов не зависит от раскладов множ наследования. А иначе выходит что подключая один и тот же класс туда-сюда мы изменяем его методы - так низзя Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Racheengel от Июль 14, 2017, 10:31 Racheengel, дело в том, что CTask содержит не одну виртуальную таблицу, а две, в каждой из которой имеется адрес на метод GetName и адреса напротив них записываются разные. Вижу, но вот это как раз и кажется странным - почему две то? Сигнатуры методов одинаковые, они оба абстракные, помечены как virtual по всему пути наследования. Я бы ожидал, что абстракный ITaskName::GetName будет помещен в VMT от CTask. Название: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: Igors от Июль 14, 2017, 11:50 Вижу, но вот это как раз и кажется странным - почему две то? Потому что наследник автоматически приводится к любому базовому типу, который не может иметь "посторонок" в VMTНазвание: Re: Возможный баг в компиляторе MSVC 2013 Отправлено: _Bers от Август 18, 2017, 08:24 Всем привет... Наткнулся на странную вещь, которую иначе как багом компилятора, объяснить трудно. вы отнаследовались от интерфейса. а реализации чисто виртуальной функции не предоставили. и почему то это у вас наследника нельзя создать? и на будущие: вместо того, что бы через одно место объяснять на пальцах, лучше привести код (на онлайн компиляторе), который наглядно иллюстрирует проблему. как это сделали моральные люди в этой самой теме. |