Lỗi kế thừa hàm virtual

Chào mn, mn xem giúp mình sao đoạn code ở dưới e nhập 1 lần thì nó tự dừng, mình cảm ơn.

#include<iostream>
#include<string.h>
using namespace std;

class ConNguoi{
	private:
		char HoTen[40];
		int Tuoi;
		char GioiTinh[10];
	public:
		virtual void nhap(){
			cout << "nhap ten:" ;
			fflush(stdin);
			gets(HoTen);
			cout << "nhap tuoi:" ;
			cin >> Tuoi;
			cout << "nhap gioi tinh:" ;
			fflush(stdin);
			gets(GioiTinh);
		}
		virtual void xuat(){
			cout << "Thong tin:" << this->HoTen << "--" << this->Tuoi << "--" << this->GioiTinh << endl;
		}
		virtual void KhenThuong(){
			
		}
};
class Sinhvien : public ConNguoi{
	private:
		char lop[20];
		float DTB;
	public:
		
		void nhap(){
			ConNguoi::nhap();
			cout << "nhap lop:";
			fflush(stdin);
			gets(this->lop);
			cout << "nhap diem:" ;
			cin >> this->DTB;
		}
		void xuat(){
			ConNguoi::xuat();
			cout << "lop:" << this->lop << ", DTB:" << this->DTB << endl; 
		}
		
};



int main(){
	ConNguoi *cn;
	cn = new Sinhvien[5];
	for(int i = 0 ; i < 5 ; i++){
		(cn+i)->nhap();
	}
	
}

thay hết các dòng fflush(stdin) thành cin.ignore(100, '\n') thử xem

edit: à chỗ này:

cn = new Sinhvien[5];

cn là con trỏ tới ConNguoi, mà mảng nó trỏ tới lại là SinhVien nên cn+i trỏ ko đúng tới SinhVien thứ i > 0. Sửa lại là:

ConNguoi** cn = new ConNguoi*[5];
for(int i = 0 ; i < 5 ; i++) {
    cn[i] = new SinhVien;
    cn[i]->nhap();
}

Vì class ConNguoi có 54 bytes nên cn + i được hiểu là cn + (54*i bytes), trong khi mảng cn trỏ tới là mảng SinhVien, mỗi SinhVien54+24=78 bytes nên cn+1 ko trỏ tới đúng SinhVien thứ 2 nằm ở vị trí cách SinhVien đầu tiên 78 bytes :V

5 Likes

B cho mình hỏi 2 dấu ** là s nhỉ. và tại sao lại cà ConNguoi*[]

2 sao là con trỏ tới con trỏ đó :V ConNguoi*[5] là mảng chứa 5 con trỏ tới con người, để tránh cn + i nó hiểu là cn + 54i. Khi cn là con trỏ tới con trỏ tới con người thì cn + icn + 8i (giả sử size con trỏ là 8), cn[i]con trỏ tới con người thứ i.

để xài đa hình thì em phải để mọi thứ là Base* (hoặc Base&) chứ ko phải Base. Ở đây em xài mảng nên tốn thêm 1 cấp con trỏ nữa (Base*) *

(ConNguoi*)* cn = new (ConNguoi*)[5];
for(int i = 0 ; i < 5 ; i++) {
    cn[i] = new SinhVien; // cn[i] là (ConNguoi*)
    cn[i]->nhap();
}

// khi dọn dẹp phải xóa dừng SinhVien rồi mới xóa mảng chứa con trỏ 
for(int i = 0 ; i < 5 ; i++) delete cn[i]; // cn[i] ko trỏ tới mảng nên chỉ xài `delete` là đủ
delete[] cn; // cn là mảng nên phải xài `delete[]`

còn vì sao phải xài Base* mà ko xài trực tiếp Base là vì Base có size cố định :V Ví dụ sizeof(Base) = B. Trong khi các lớp kế thừa từ BaseDerived1, Derived2 có thể có kích cỡ khác Base và khác nhau đôi một nữa :V B != D1, B != D2, D1 != D2 chẳng hạn. Khi tạo 1 mảng chỉ chứa n Base thì C++ nó rất thật thà tạo đúng n*B bytes :V Nếu em muốn chứa mảng gồm Base-Derived1-Derived2-Derived2-Derived1-Base-Derived1 sẽ ko tạo được, vì nó có kích cỡ ko đều: [B][D1][D2][D2][D1][B][D1] mà phải tạo mảng gồm con trỏ Base: Base*-Base*-Base*-Base*-Base*-Base*-Base*, mỗi con trỏ trỏ tới Base hoặc Derived1, Derived2 tùy thích. Khi này kích thước trong mảng đều giống như là 8 chẳng hạn: [8][8][8][8][8][8][8]

Hay mảng chứa n Derived1 thì nó tạo mảng đúng n*D1 bytes, phần tử thứ i sẽ cách phần tử đầu tiên D1*i bytes. Vì vậy nếu xài con trỏ Base* b trỏ tới mảng Derived1 này sẽ chạy ko đúng vì b + i nó hiểu là phần tử cách b đúng B*i bytes, trong khi phần tử thứ i trong mảng Derived1 nằm cách phần tử đầu tiên D1*i bytes, nếu B != D1 thì lỗi, thậm chí B==D1 vẫn có thể có lỗi :V Cách xử lý là xài thêm 1 cấp con trỏ nữa cho kích cỡ nó đồng đều, vì con trỏ tới kiểu X Y Z gì thì cũng chỉ có kích cỡ của con trỏ là 8 bytes (4 bytes nếu compile target 32-bit)

cn trỏ sai:

địa chỉ: ?          ?+78       ?+78*2     ?+78*3     ?+78*4
mảng:    [SinhVien1][SinhVien2][SinhVien3][SinhVien4][SinhVien5]
         ^      ^      ^      ^      ^
con trỏ  cn     cn+1   cn+2   cn+3   cn+4
giá trị  ?      ?+54   ?+54*2 ?+54*3 ?+54*4 

cn = con trỏ tới (ConNguoi)

cn trỏ đúng:

địa chỉ: ?            ?+8          ?+8*2        ?+8*3        ?+8*4
mảng:    [ConNguoi* 1][ConNguoi* 2][ConNguoi* 3][ConNguoi* 4][ConNguoi* 5]
         ^            ^            ^            ^            ^
con trỏ  cn           cn+1         cn+2         cn+3         cn+4
giá trị  ?            ?+8          ?+8*2        ?+8*3        ?+8*4

cn = con trỏ tới (ConNguoi*)
ConNguoi* i có thể trỏ đến ConNguoi hoặc SinhVien tùy ý
4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?