2010-03-09 9 views
10

[Tất cả những điều sau đây đã được thử nghiệm sử dụng Visual Studio 2008 SP1]C++ so với C++/CLI: trình độ chuyên môn Const chức năng ảo thông số

Trong C++, trình độ const các loại tham số không ảnh hưởng đến các loại của một hàm (8.3.5/3: "Bất cứ cv-vòng loại thay đổi một kiểu tham số này sẽ bị xóa")

vì vậy, ví dụ, trong hệ thống phân cấp lớp sau, Derived::Foo ghi đè Base::Foo:

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

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

Xem xét một hệ thống cấp bậc tương tự trong 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 { } 
}; 

Nếu tôi sau đó tạo ra một thể hiện của Derived:

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

nó biên dịch mà không có lỗi hoặc cảnh báo. Khi tôi chạy nó, nó ném ngoại lệ sau đây và sau đó chấm dứt:

An unhandled exception of type 'System.TypeLoadException' occurred in ClrVirtualTest.exe

Additional information: Method 'Foo' in type 'Derived'...does not have an implementation.

ngoại lệ Đó dường như chỉ ra rằng trình độ const của tham số không ảnh hưởng đến kiểu của hàm trong C++/CLI (hoặc, ít nhất nó ảnh hưởng đến trọng số theo một cách nào đó). Tuy nhiên, nếu tôi nhận xét ra các dòng có chứa các định nghĩa của Derived::Foo, trình biên dịch báo cáo lỗi sau (trên dòng trong main nơi thể hiện của Derived được khởi tạo):

error C2259: 'Derived': cannot instantiate abstract class

Nếu tôi thêm các vòng loại const đến tham số của Derived::Foo hoặc xóa vòng loại const khỏi tham số Base::Foo, nó biên dịch và chạy không có lỗi.

Tôi nghĩ rằng nếu trình độ const của tham số ảnh hưởng đến loại hàm, tôi sẽ gặp lỗi này nếu trình độ const của tham số trong hàm lớp ảo có nguồn gốc không khớp với trình độ const của tham số trong hàm ảo lớp cơ sở.

Nếu tôi thay đổi kiểu của tham số Derived::Foo 's từ một int đến một double, tôi nhận được những điều sau đây cảnh báo (ngoài các lỗi nói trên, C2259):

warning C4490: 'override': incorrect use of override specifier; 'Derived::Foo' does not match a base ref class method

Vì vậy, câu hỏi của tôi là, hiệu quả, liệu trình độ const của các tham số chức năng có ảnh hưởng đến loại hàm trong C++/CLI không? Nếu vậy, tại sao điều này biên dịch và tại sao không có lỗi hoặc cảnh báo? Nếu không, tại sao là một ngoại lệ ném?

+0

Cập nhật: Tôi đã báo cáo lỗi này trên Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/540788 (Tôi đã sao chép liên kết đến đây từ cuộc thảo luận dưới đây vì nó đã được chôn cất trong cuộc hội thoại) –

+0

Thành viên nhóm biên dịch Microsoft C++/CLI đã xác nhận là vào ngày 21 tháng 3 rằng đó là lỗi và họ đang khám phá tác động của bản sửa lỗi trên mã hiện có. –

+0

@Ben: Cảm ơn. Lỗi mà tôi đã gửi trên Microsoft Connect đã bị đóng hôm nay là "không khắc phục được". "Xin chào: cảm ơn vì đã báo cáo vấn đề này. Thật không may dựa trên phân tích của chúng tôi về mức độ nghiêm trọng của vấn đề này kết hợp với các lần giới hạn của chúng tôi, chúng tôi sẽ không thể khắc phục vấn đề này trong bản phát hành tiếp theo của Visual C++." Oh well :-) –

Trả lời

8

Vâng, đó là lỗi. Các công cụ sửa đổi const được phát ra vào siêu dữ liệu với công cụ sửa đổi tùy chỉnh modopt. Thật không may, các quy tắc ngôn ngữ C++/CLI không phù hợp với các quy tắc CLI. Chương 7.1.1 của thông số CLI nói:

Custom modifiers, defined using modreq (“required modifier”) and modopt (“optional modifier”), are similar to custom attributes (§21) except that modifiers are part of a signature rather than being attached to adeclaration. Each modifer associates a type reference with an item in the signature.

The CLI itself shall treat required and optional modifiers in the same manner. Two signatures that differ only by the addition of a custom modifier (required or optional) shall not be considered to match. Custom modifiers have no other effect on the operation of the VES.

Vì vậy, CLR nói rằng Derived :: Foo() không phải là ghi đè, C++/CLI cho biết. CLR thắng.

Bạn có thể báo cáo lỗi tại connect.microsoft.com nhưng có thể lãng phí thời gian. Tôi nghĩ rằng sự không tương thích này là cố ý. Họ nên đã thay đổi các quy tắc ngôn ngữ cho C++/CLI nhưng chắc chắn rằng khả năng tương thích C++ là quan trọng hơn.CV sửa đổi là một đau anyway, có những kịch bản khác mà không được hỗ trợ tốt, const con trỏ đến const cho một. Điều này không thể được thực thi trong thời gian chạy anyway, CLR không có hỗ trợ cho nó.

+0

Cảm ơn bạn. Tôi đã nhìn vào spec C++/CLI, nhưng không nghĩ đến việc tìm kiếm thông số CLI. Không được sử dụng .NET nhiều, tôi không biết về sự hỗ trợ hạn chế của CLI đối với trình độ const cho đến khi tôi bắt đầu đào sâu vào vấn đề này. Theo dõi, có lý do nào mà trình biên dịch C++/CLI không thể bỏ qua công cụ sửa đổi tùy chỉnh khi nó tạo ra IL? –

+0

Nó không thể, nó tải các định nghĩa lớp từ siêu dữ liệu lắp ráp. Không phải tệp tiêu đề. Những định nghĩa cần phải được mã hóa sử dụng các khả năng siêu dữ liệu. Bỏ qua vòng loại CV hoàn toàn chúng ta sẽ không tương thích. –

+0

Điều đó nghe có vẻ như bạn sẽ có một hành vi khác nếu bạn chỉ cần #bao gồm tiêu đề từ cùng một thư viện so với việc gọi một tệp DLL khác ... Crazy :( –

3

Đó là lỗi và không cụ thể với C++/CLI.

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

Thực tế là, cáC++ biên dịch C có nghĩa vụ phải lột top-level const/dễ bay hơi. Chỉ const/volatile trên kiểu trỏ đến một con trỏ hoặc các vấn đề tham chiếu. Nếu trình biên dịch đã làm điều đó một cách chính xác, CLR sẽ không có một tiếng nói trong những gì đang xảy ra.

BTW đây là IL được tạo ra bởi trình biên dịch với/clr: tinh khiết

.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 
    } 

} 

này chắc chắn vi phạm quy tắc James liệt kê liên quan đến xoá vòng loại cấp cao nhất.

phận có liên quan tiếp theo của spec C++/CLI:

8.8.10.1 Function overriding

[snip]

  1. A derived class function explicitly overrides a base class virtual function having the same name, parameter-type-list, and cv-qualification, by using the function modifier override, with the program being ill-formed if no such base class virtual function exists

12.3 Declarator types

The C++ Standard (§8.3.5/3) is augmented, as follows:
The resulting list of transformed parameter types and the presence or absence of the ellipsis is the function’s parameter-type-list.

Vì vậy, tôi đang dẫn dắt để tin rằng các quy tắc về xóa cv-vòng loại áp dụng cho C++/CLI là tốt, vì spec kêu gọi cụ thể phần 8.3.5/3 của tiêu chuẩn ISO C++.

+0

Đối với mã gốc, lỗi đó đã được sửa, ít nhất là VS2008 SP1 (trình biên dịch thậm chí còn đưa ra cảnh báo, C4373, "các phiên bản trước của trình biên dịch đã không ghi đè khi tham số chỉ khác nhau bởi const/volatile qualifiers"). Tôi chỉ có thể tái tạo vấn đề được đề cập trong bài đăng gốc với các loại CLI (nghĩa là các loại 'lớp ref '). –

+0

@ James, tôi đồng ý rằng mã repro của tôi cuối cùng không gây ra vấn đề với VS2008 SP1 (sửa chữa đầu tiên đã không thực sự sửa chữa nó). Và tôi có thể repro vấn đề của bạn, kể từ khi bạn liệt kê một lỗi trên Connect tôi sẽ xác nhận nó. –