C ++ против C ++ / CLI: Const квалификация параметров виртуальной функции - PullRequest
10 голосов
/ 10 марта 2010

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

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

Так, например, в следующей иерархии классов 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;
}

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

Произошло необработанное исключение типа «System.TypeLoadException» в ClrVirtualTest.exe

Дополнительная информация: Метод 'Foo' в типе 'Derived' ... не имеет реализации.

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

ошибка C2259: «Производное»: не удалось создать экземпляр абстрактного класса

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

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

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

предупреждение C4490: «переопределить»: неправильное использование спецификатора переопределения; Derived :: Foo не соответствует методу базового класса ref

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

Ответы [ 2 ]

8 голосов
/ 10 марта 2010

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

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

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

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

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

3 голосов
/ 10 марта 2010

Это ошибка, и она не относится к 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 Переопределение функций

[надрез]

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...