2015-07-25 18 views
5

Tôi đã gặp phải một hành vi khá lạ khi sử dụng tự động và dynamic_cast. Đây là lớp hệ thống phân cấp tôi có:động đúc tham chiếu và tự động

class BaseInterface { 
public: 
    virtual void someMethod()=0; 
}; 

class Derived:public BaseInterface { 
public: 
    virtual void someMethod1()=0; 
    void someMethod()override; 
}; 

Và tất nhiên có một số lớp học mà thực hiện tất cả các phương pháp có nguồn gốc.

Tiếp theo là một lớp thứ ba mà trông như thế này:

class ThirdClass { 
public: 
    void demoMethod(BaseInterface&); 
    void anotherMethod(Derived&); 
}; 

void ThirdClass::demoMethod(BaseInterface& obj) { 
    auto buffer=dynamic_cast<Derived&>(obj); 
    anotherMethod(buffer); 
} 

Khi tôi biên dịch này với gcc tôi nhận được một "không thể phân bổ một đối tượng kiểu trừu tượng" lỗi. Trong khi đó, khi tôi thay

auto buffer=... 

với

Derived& buffer=... 

tất cả mọi thứ biên dịch tốt. Tại sao lại như vậy? Là tự động không deducing đúng loại hoặc một cái gì đó?

Ngoài ra tôi tìm thấy một thủ thuật bẩn để vẫn sử dụng auto:

void ThirdClass::demoMethod(Base& obj) { 
    auto buffer=dynamic_cast<Derived*>(&obj); 
    anotherMethod(*buffer); 
} 
+4

Tôi đoán 'tự động 'loại trừ loại' Bộ đệm có nguồn gốc', không phải là 'Nguồn gốc & bộ đệm'. – melpomene

+0

Bạn đang sử dụng phiên bản g ++ nào? Hoạt động tốt để biên dịch mã của bạn [sau khi sửa lỗi chính tả như không có kiểu trả về 'demoMethod' và không thừa kế trên' derived'] - cả hai clang ++ 3.7 (khoảng hai tuần tuổi) và g ++ 4.9.2. –

+0

@MatsPetersson: Nếu kiểu trả về bị thiếu là cố định, nó bị lỗi theo cách được báo cáo với bất kỳ ideone trình biên dịch nào sử dụng: http://ideone.com/UEtfui –

Trả lời

6

Bạn đang nhận Derived từ auto. Sử dụng điều này thay vì:

auto & buffer = dynamic_cast<Derived&>(obj); 
5

§7.1.6.4/7:

Khi một biến khai báo sử dụng một loại placeholder được khởi tạo [...] kiểu trả về suy luận hoặc kiểu dữ liệu được xác định từ loại của trình khởi tạo của nó. […] Hãy để T là loại được khai báo của biến số hoặc loại trả về của hàm. Nếu trình giữ chỗ là auto loại-specifier, loại suy luận được xác định bằng cách sử dụng các quy tắc cho khấu trừ đối số mẫu. […] có được P từ T bằng cách thay thế lần xuất hiện của auto bằng mẫu loại phát minh mới thông số U […]. Giảm giá trị cho U bằng các quy tắc của mẫu khấu trừ đối số từ cuộc gọi hàm (14.8.2.1), trong đó P là loại tham số mẫu chức năng và đối số tương ứng là khởi tạo.

Vì vậy, để làm quen với quá trình này, hãy nhìn vào sự cai trị thực tế sử dụng để suy diễn ra loại buffer: Điều gì sẽ xảy ra nếu bạn thay đổi

template <typename U> 
void f(U); 

để

void f(Derived&); 

khi gọi f với giá trị loại Derived? Rõ ràng, đối với mẫu chức năng, U sẽ được suy ra là Derived, sau đó mang lại một lỗi khấu trừ.
Điều này trực tiếp tương ứng với việc khấu trừ loại trình giữ chỗ trong ví dụ của bạn - auto sẽ được thay thế bằng Derived và không thành công, vì Derived là trừu tượng.

Nói chung, nếu bạn viết

auto obj = …; 

obj sẽ không bao giờ là một tài liệu tham khảo, cũng giống như U sẽ không bao giờ được suy diễn như một loại tài liệu tham khảo khi gọi hàm mẫu ở trên.


Thay vào đó, sử dụng auto&:

auto& buffer = dynamic_cast<Derived&>(obj); 

Bây giờ, PU&:

template <typename U> 
void f(U&); 

U là, tất nhiên, vẫn còn suy luận như Derived, nhưng loại P - mà có hiệu quả là loại buffer - là Derived&.

+2

lol, "rõ ràng" –

+0

@LightnessRacesinOrbit Vâng, tôi thấy rằng người hỏi được sử dụng để trích mẫu đối số :) – Columbo

+0

@Columbo Thành thật mà nói thì không. Tôi chỉ bắt đầu với C++ như 3 tháng trước và havent stumbled qua mẫu nào được nêu ra. – SuppenGeist

Các vấn đề liên quan