Câu trả lời ngắn gọn: Trong C++, mảng giá trị không bao giờ đa hình, ngay cả khi nội dung của chúng là và không thể được xử lý như vậy. Tức là, bạn không thể xem một số derived ad[N]
như thể đó là base ab[N]
.
Câu trả lời dài: Lý do cho điều này được chôn sâu trong số học con trỏ của C. Nếu bạn có một số int* pi
và tăng nó ++pi
, nó sẽ không đơn giản tăng lên đến địa chỉ bộ nhớ tiếp theo. Nếu nó đã làm, nó sẽ không trỏ đến int
tiếp theo vì điều này không bắt đầu tại địa chỉ tiếp theo. Vì vậy, thay vào đó, sizeof(int)
byte được thêm vào con trỏ. (Ví dụ cụ thể có thể giúp: Trên các kiến trúc có 8bit char
loại - char
, theo định nghĩa C và C++ xem xét kích thước byte của kiến trúc - và 32bit int
loại, int
có kích thước 4 byte, như vậy, ++pi
sẽ thêm 4 vào địa chỉ con trỏ, để nó trỏ đến int
tiếp theo.) Số học tương tự áp dụng cho tất cả các thao tác con trỏ khác. Vì vậy, ví dụ, với int* pi2=pi+1
, pi2
sẽ chỉ sizeof(int)
byte đằng sau pi
, mặc dù pi2-pi
sẽ mang lại 1.
Vì vậy, giả sử bạn hiểu đoạn cuối cùng, chúng ta hãy quay trở lại với mảng. Nếu bạn có một mảng derived ad[N]
, địa chỉ của ad[1]
là sizeof(derived)
byte lớn hơn địa chỉ ad[0]
.Tuy nhiên, nếu bạn có một base* pb
trỏ đến ad[0]
, tăng nó sẽ làm cho nó điểm sizeof(base)
đằng sau địa chỉ của phần tử đầu tiên - trong đó, nếu (như trường hợp trong ví dụ của bạn) sizeof(base) < sizeof(derived)
, là không phải địa chỉ ad[1]
, nhưng ở đâu đó ở giữa ad[0]
.
Điều duy nhất bạn có thể làm để điều trị nội dung mảng như thể nó là tất cả các lớp học cơ sở, là để lặp qua mảng bằng cách sử dụng một derived*
và đúc con trỏ này để base*
trong vòng lặp:
derived d[5];
derived* begin = d;
const derived* end = d + sizeof(d)/sizeof(d[0]); // points one beyond the last element
while(begin != end)
{
base* pb = begin;
cout<< pb->_bval;
++begin;
}
(Lưu ý rằng tôi cũng đã thay đổi mã của bạn để sử dụng trình lặp bắt đầu/kết thúc thành ngữ của C++).
Cảm ơn bạn đã chính xác. –