C++ по сравнению с C++ / CLI: квалификация Константы параметров виртуальной функции

[Все следующее было протестировано с помощью Visual Studio 2008 SP1]

В C++ квалификация константы типов параметра не влияет на тип функции (8.3.5/3: "Любой спецификатор условной цены, изменяющий тип параметра, удален"),

Так, например, в следующей иерархии классов, Derived::Foo переопределения Base::Foo:

struct Base
{
    virtual void Foo(const int i) { }
};

struct Derived : Base
{
    virtual void Foo(int i) { }
};

Считайте подобную иерархию в C++ / CLI:

ref class Base abstract
{
public:
    virtual void Foo(const int) = 0;
};

ref class Derived : public Base
{
public:
    virtual void Foo(int i) override { }
};

Если я затем создаю экземпляр Derived:

int main(array<System::String ^> ^args)
{
    Derived^ d = gcnew Derived;
}

это компилирует без ошибок или предупреждений. Когда я выполняю его, это выдает следующее исключение и затем завершается:

Необработанное исключение типа 'Система. TypeLoadException' произошел в ClrVirtualTest.exe

Дополнительная информация: Метод 'Нечто' в типе, 'Полученном'..., не имеет реализации.

То исключение, кажется, указывает, что квалификация константы параметра действительно влияет на тип функции в C++ / CLI (или, по крайней мере, это влияет на переопределение в некотором роде). Однако, если я комментирую строку, содержащую определение Derived::Foo, компилятор сообщает о следующей ошибке (на строке в main где экземпляр Derived инстанцирован):

ошибка C2259: 'Полученный': не может инстанцировать абстрактного класса

Если я добавляю спецификатор константы к параметру Derived::Foo или удалите спецификатор константы из параметра Base::Foo, это компилирует и работает без ошибок.

Я думал бы, что, если квалификация константы параметра влияет на тип функции, я должен получить эту ошибку, если квалификация константы параметра в виртуальной функции производного класса не соответствует квалификации константы параметра в виртуальной функции базового класса.

Если я изменяю тип Derived::Fooпараметр от int к a double, Я получаю соблюдающее предупреждение (в дополнение к вышеупомянутой ошибке, C2259):

предупреждение C4490: 'переопределение': неправильное использование спецификатора переопределения; 'Полученный:: Нечто' не соответствует основе касательно метода класса

Так, мой вопрос, эффективно, делает квалификацию константы влияния параметров функции тип функции в C++ / CLI? Если так, почему это компилирует и почему не там никакие ошибки или предупреждения? В противном случае, почему исключение выдается?

10
задан Deduplicator 9 March 2015 в 20:21
поделиться

2 ответа

Что ж, это ошибка. Модификаторы const передаются в метаданные с помощью настраиваемого модификатора modopt. К сожалению, правила языка C ++ / CLI не соответствуют правилам CLI. В главе 7.1.1 спецификации CLI говорится:

Пользовательские модификаторы, определенные с помощью modreq («обязательный модификатор») и modopt («необязательный модификатор»), аналогичны {{1 }} настраиваемые атрибуты (§21), за исключением того, что модификаторы являются частью подписи , а не прикрепляются к объявлению . Каждый модификатор связывает ссылку на тип с элементом в сигнатуре .

Сам CLI должен обрабатывать обязательные и необязательные модификаторы одинаково . Две подписи, которые отличаются только добавлением специального модификатора (обязательного или необязательного), не считаются совпадающими. Пользовательские модификаторы не имеют другого влияния на работу VES.

Итак, CLR говорит, что Derived :: Foo () не является переопределением, а C ++ / CLI говорит, что это так. CLR побеждает.

Вы можете сообщить об ошибке на сайте connect.microsoft.com, но, вероятно, это пустая трата времени. Я думаю, эта несовместимость была намеренной. Им следовало изменить языковые правила для C ++ / CLI, но определенно считали совместимость с C ++ более важной. В любом случае модификаторы CV - это боль, есть другие сценарии, которые не очень хорошо поддерживаются, например, указатели const на const. В любом случае это не может быть применено во время выполнения, среда CLR не поддерживает этого.

8
ответ дан 4 December 2019 в 01:00
поделиться

Это ошибка, не относящаяся к C ++ / CLI.

https://connect.microsoft.com/VisualStudio/feedback/details/100917/argument-const-ness-is-part-of-member-function-type-signature

Фактически, компилятор C ++ предполагается убрать верхний уровень const / volatile. Только const / volatile для указанного типа указателя или ссылки. Если бы компилятор сделал это правильно, CLR не имела бы права голоса в том, что происходит.

Кстати, это IL, сгенерированный компилятором с помощью / clr: pure

.class private abstract auto ansi beforefieldinit Base
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 1
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }

    .method public hidebysig newslot abstract virtual instance void Foo(int32 modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) cil managed
    {
    }

}

.class private auto ansi beforefieldinit Derived
    extends Base
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 1
        L_0000: ldarg.0 
        L_0001: call instance void Base::.ctor()
        L_0006: ret 
    }

    .method public hidebysig virtual instance void Foo(int32 i) cil managed
    {
        .maxstack 0
        L_0000: ret 
    }

}

Это определенно нарушает указанное Джеймсом правило, касающееся удаления квалификаторов верхнего уровня.

Дополнительные соответствующие разделы спецификации C ++ / CLI:

8.8.10.1 Переопределение функции

[snip]

  1. Функция производного класса явно переопределяет виртуальную функцию базового класса с тем же именем, списком типов-параметров и cv- квалификация, используя переопределение модификатора функции, при этом программа плохо сформирована, если такая виртуальная функция базового класса не существует

12.3 Типы деклараторов

Стандарт C ++ (§8.3.5 / 3) дополняется следующим образом:
Результирующий список преобразованных типов параметров и наличие или отсутствие многоточия - это список типов параметров функции.

Итак, я пришел к выводу, что правило удаления cv-квалификаторов применимо и к C ++ / CLI, потому что в спецификации специально упоминается раздел 8.3.5 / 3 стандарта ISO C ++.

3
ответ дан 4 December 2019 в 01:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: