2010-01-26 33 views
5
#include <vector> 

struct A {int a;}; 
struct B : public A {char b;}; 

int main() 
{ 
    B b; 
    typedef std::pair<A*, A*> MyPair; 
    std::vector<MyPair> v; 
    v.push_back(std::make_pair(&b, &b)); //compiler error should be here(pair<B*,B*>) 
    return 0; 
} 

Tôi không hiểu tại sao điều này biên dịch (có thể ai đó vui lòng có thể cung cấp giải thích chi tiết? Có điều gì đó liên quan đến tên nhìn lên?C++ mẫu đúc với các lớp học có nguồn gốc

Btw, trên Solaris, SunStudio12 nó không biên dịch: error : formal argument x of type const std::pair<A*, A*> & in call to std::vector<std::pair<A*,A*> >::push_back(const std::pair<A*, A*> &) is being passed std::pair<B*, B*>

+4

Mẫu cấu trúc trên không thực sự làm được nhiều? – BenG

+0

@BennyG: Nó nghe về một số rắc rối trong khu phố và quyết định đến và có một cái nhìn. –

+0

xin lỗi, xóa nó – yurec

Trả lời

13

std::pair có một mẫu nhà xây dựng:

template<class U, class V> pair(const pair<U, V> &p); 

"Hiệu ứng: Khởi tạo thành viên từ các thành viên tương ứng của đối số, thực hiện chuyển đổi ngầm khi cần." (C++ 03, 20.2.2/4)

Chuyển đổi từ một con trỏ lớp dẫn xuất sang con trỏ lớp cơ sở là tiềm ẩn.

+1

+1 cho câu trả lời ngắn và chính xác :-) –

+0

Tôi không thuyết phục, make_pair là một hàm mẫu, loại trừ các loại từ đối số. Đúng? – yurec

+2

Có, và nó tạo ra một cặp 'std :: (B *, B *)'. Sau đó nó sử dụng hàm tạo ở trên để xây dựng một cặp 'std :: (A *, A *)'. – GManNickG

0

Vì B có nguồn gốc từ A, v vectơ sẽ chứa con trỏ tới cấu trúc lớp cơ sở của đối tượng b. do đó, bạn có thể truy cập vào các thành viên của A, tức là

std::cout << v[0].first->a; 

EDIT: sai lầm của tôi, như chỉ ra dưới đây, bạn vẫn có thể cast vào con trỏ loại B vì các vector là của con trỏ, không đối tượng, vì vậy không đối tượng slicing đã xảy ra.

Một cuộc gọi như

std::cout << v[0].first->b; 

sẽ không biên dịch từ các yếu tố trong vector là cơ sở con trỏ lớp và không thể trỏ đến các thành viên lớp được thừa kế mà không có một dàn diễn viên, tức là

std::cout << static_cast<B*>(v[0].first)->b; 

Cũng lưu ý rằng một dàn diễn viên năng động, như trong

std::cout << dynamic_cast<B*>(v[0].first)->b; 

sẽ không biên dịch với lỗi sau trong gcc:

cast.cpp:14: error: cannot dynamic_cast ‘v.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::pair<A*, A*>, _Alloc = std::allocator<std::pair<A*, A*> >](0u)->std::pair<A*, A*>::first’ (of type struct A*’) to type struct B*’ (source type is not polymorphic) 
+2

Các thành viên của lớp B không bị mất, và loại động của các đối tượng được trỏ đến vẫn là B. Các thành viên của B vẫn có thể được truy cập: 'static_cast (v [0] .first) -> b' (mặc dù trong trường hợp này, một 'dynamic_cast' có lẽ sẽ thích hợp hơn). –

+0

@tmatth: Như James McNellis nói, bạn vẫn có thể truy cập các thành viên lớp có nguồn gốc thông qua một dàn diễn viên. Có lẽ bạn đang nghĩ đến việc cắt đối tượng? Điều đó chỉ xảy ra khi sử dụng một vectơ các đối tượng ('A'), không phải là một vectơ của con trỏ (' A * '). Trong trường hợp đó, có, các thành viên của 'B' sẽ âm thầm bị loại bỏ. –

+0

tôi đã chỉnh sửa để phản ánh phản hồi của bạn, hy vọng điều này sẽ xóa nó. – tmatth

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