2010-07-12 18 views
7

Biên dịch mã này sử dụng g ++ 4.2.1:Lớp cơ sở riêng không chính đáng không thể truy cập?

struct S { }; 
template<typename T> struct ST { }; 

template<typename BaseType> 
class ref_count : private BaseType { }; 

template<typename RefCountType> 
class rep_base : public RefCountType { }; 

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<S> > base_type;  // line 11 
}; 

tôi nhận được:

bug.cpp:1: error: ‘struct S’ is inaccessible 
bug.cpp:11: error: within this context 

Tuy nhiên, nếu tôi thay đổi lớp wrap_rep sử dụng ST:

class wrap_rep : public rep_base<ref_count< ST<int> > > { 
    typedef rep_base<ref_count< ST<int> > > base_type; 
}; 

nó biên dịch tốt . Ngoài ra, nếu tôi thay đổi mã ban đầu thành:

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<::S> > base_type; // now using :: 
}; 

nó cũng biên dịch tốt. Đối với tôi, mã ban đầu có vẻ ổn như vậy. Đây có phải là lỗi g ++ không? Nếu không, thì tại sao sử dụng mẫu làm việc? Và, đối với trường hợp khác, tại sao cần ::S?

Trả lời

7

Cả hai mã đó đều không hợp lệ (chỉ có mã cuối cùng hợp lệ), nhưng trình biên dịch của bạn (không phù hợp) chỉ chẩn đoán một mã. Như một câu trả lời khác nói, điều này sử dụng tên lớp được tiêm. Một lớp học S được coi là có một tên thành viên S biểu thị cùng một lớp. Ví dụ (chú ý "class" từ khóa trước khi S::S trong ví dụ đầu tiên là cần thiết để buộc một tham chiếu đến tên lớp tiêm, thay vì constructor mặc định):

class S { }; 

class S::S object; // creates an S object 
class X : S::S::S::S { }; // derives from class S 

Lớp mẫu cũng có một tên lớp tiêm. Giống như tên lớp được tiêm, nó được kế thừa cho các lớp dẫn xuất, và do đó ST<int> là không đúng định dạng vì nó sử dụng tên lớp được tiêm đó, tuy nhiên không thể truy cập được. Nếu bạn sử dụng GCC ít 4.5, nó có thể có cái gì để làm với một change introduced với GCC4.5:

G ++ nay thực hiện DR 176. Trước đây G ++ không hỗ trợ sử dụng tiêm-class-name của một lớp mẫu cơ sở dưới dạng tên loại và tra cứu tên tìm thấy khai báo của mẫu trong phạm vi kèm theo. Bây giờ tra cứu tên tìm thấy tên lớp được tiêm, có thể được sử dụng làm kiểu hoặc dưới dạng mẫu, tùy thuộc vào việc tên đó có được theo sau bởi danh sách đối số khuôn mẫu hay không. Như một kết quả của sự thay đổi này, một số mã mà trước đây đã được chấp nhận có thể được vô hình thành vì

  1. Các tiêm-class-name là không thể truy cập bởi vì nó là từ một cơ sở tư nhân, hoặc
  2. Các tiêm-class- không thể sử dụng tên làm đối số cho tham số mẫu mẫu.

Trong một trong các trường hợp này, mã có thể được sửa bằng cách thêm một trình đặt tên-lồng nhau để đặt tên mẫu rõ ràng. Việc đầu tiên có thể được làm việc xung quanh với -fno-access-control; thứ hai chỉ bị từ chối với -pantic.


Để có nhiều niềm vui hơn một chút với tên lớp tiêm - nhận thấy rằng các tên lớp tiêm không phải là tương đương với một typedef như người ta vẫn nghĩ đầu tiên. Tên lớp tiêm là một đẳng cấp tên, nhưng không được phân loại như một typedef tên tuổi, có nghĩa là nó có thể được ẩn bằng chức năng, đối tượng hoặc điều tra viên tên:

// valid, the data-member hides the injected class name 
struct S { int S; }; 

Để tham khảo các tên lớp tiêm bạn có thể nói class S::S (tương tự như vậy, trong danh sách lớp cơ sở, các tên không phải kiểu được bỏ qua, do đó bạn không cần chú ý đặc biệt ở đó), nhưng tra cứu đơn giản là S::S sẽ tham chiếu đến thành viên dữ liệu.

0

Mã gốc được biên dịch tốt trong "Bản cập nhật Sun WorkShop 6 2 Trình biên dịch C++". Đây là người duy nhất tôi có quyền truy cập vào văn phòng của tôi. Có thể thử trên bất kỳ trình biên dịch nào khác mà bạn có.

3

Cấu trúc của bạn S là lớp cơ sở là wrap_rep có nghĩa là nó được tiêm vào wrap_rep như thể có một typedef ẩn danh.

Sử dụng toán tử :: trước S trong typedef sẽ cho trình biên dịch của bạn không sử dụng S mà bạn kế thừa từ, nhưng S trong không gian tên chung.

Xem this link.

+0

Nhưng sau đó tại sao mã hoạt động với một lớp cơ sở mẫu? –