2014-07-01 15 views
5

Tôi đã học C++ templating và tôi đã chạy trên một số hành vi kỳ lạ. Xem xét cấu trúc lớp này (rút gọn từ mã ban đầu của tôi):Truy cập các đối tượng được thừa kế từ mẫu lớp

class A { 
public: 
    std::vector <int> vec; 
}; 

template <typename T> class B : public A { }; 

template <typename T> class C : public B<T> { 
public: 
    using A::vec; 
    int test() { 
     return vec[1];  // OK 
    } 

    int test2() { 
     return vec.size(); // error: 'class A' has no member named 'size' 
    } 
}; 

Khi biên dịch, tôi nhận được một lỗi trong test2, nói rằng class A không có thành viên size. Nhưng vec phải là đối tượng vector, không phải là một thể hiện của A. Thật vậy, nếu tôi lấy được C trực tiếp từ A thay vì B<T> hoặc xóa mẫu khỏi C, nó sẽ biên dịch tốt.

Hơn nữa, nếu tôi thêm các phương pháp sau đây để C:

int test3() { 
    void ***v = vec;  // error: cannot convert from 
          // 'std::vector<int,...>' to 'void***' 
} 

trình biên dịch nói nó không thể chuyển đổi từ một vector<int> để void***, vì vậy nó có vẻ biết đúng loại cho vec. Tôi có mắc lỗi ở đây không, hoặc đây có phải là lỗi trong trình biên dịch của tôi không? Tôi đang sử dụng phiên bản g ++ 4.2.1 của Apple. Chỉnh sửa: cũng dường như xảy ra trong các phiên bản sau của g ++.

Cảm ơn sự giúp đỡ của bạn!

Second chỉnh sửa: trình biên dịch của tôi là hạnh phúc nếu tôi sử dụng this->vec.size() trong test2 thay vì dựa vào những tuyên bố using A::vec.

+0

[Tại sao tôi phải để truy cập các thành viên lớp cơ sở mẫu thông qua con trỏ này?] (Http://stackoverflow.com/ q/4643074/341970) – Ali

Trả lời

2

Đầu tiên, mã của bạn biên dịch bằng tiếng kêu (xem here) và không biên dịch với gcc. Tôi cũng có nó để biên dịch với VS2013.


vấn đề ban đầu của bạn có liên quan đến cách thức tên trình biên dịch tra cứu trong các mẫu.

Tiêu chuẩn § 14.6.2:

tên không phụ thuộc vào sử dụng trong một khuôn mẫu định nghĩa được tìm thấy bằng cách sử dụng tra cứu tên thông thường và ràng buộc tại thời điểm chúng được sử dụng.

Ngoài ra C++ FAQ có một mục tốt về nó:

Trình biên dịch không giống trong các lớp cơ sở phụ thuộc (như B) khi nhìn lên tên nondependent (như vec).


Giải pháp:

1. Sử dụng this->vec (điều này luôn luôn là ngầm phụ thuộc trong một mẫu)

int test2() { 
    return this->vec.size(); 
} 

2. Sử dụng using B<T>::vec

3. Sử dụng B<T> trực tiếp:

int test2() { 
    return B<T>::vec.size(); 
} 

Ghi chú:

  • Tôi không chắc chắn lý do tại sao gcc từ chối using A::vec;, trông giống như một trình biên dịch lỗi với tôi (và lưu ý rằng using B<T>::A::vec; công trình).
  • tài liệu tham khảo chuẩn cho tra cứu tên mẫu: § 14.6.3 và § 14.6.4
+0

Cảm ơn câu trả lời của bạn! Tôi đọc nhanh về vấn đề với các tên không phụ thuộc và các lớp cơ sở phụ thuộc (và đó là nơi tôi đã học được cú pháp 'using A :: vec'). Nhưng, tôi không biết bạn có thể ngăn xếp các nhà khai thác độ phân giải phạm vi như B :: A :: vec - đó là điều tốt để biết. –

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