01/10/2018, 11:44
Hỏi cách sử dụng Lớp cơ sở trừu tượng trong C++
Tôi là newbie đang bắt đầu tự học lập trình qua đọc sách là chủ yếu. Hiện tại đang gặp vấn đề ở phần ví dụ của Lớp cơ sở trừu tượng, nhờ các Tiền Bối chỉ bảo dùm.
#include <iostream>
#include <math.h>
using namespace std;
class Point
{
protected:
float x, y;
public:
float& getX(void);
float& getY(void);
virtual float KhoangCach(void*)=0;
};
float& Point::getX(void)
{
return x;
}
float& Point::getY(void)
{
return y;
}
class Point2D:public Point
{
public:
float KhoangCach(void*);
};
class Point3D:public Point
{
float z;
public:
float& getZ(void);
float KhoangCach(void*);
};
float Point2D::KhoangCach(void* p)
{
Point2D* q = (Point2D*)(p);
return sqrt(pow(q->x-x,2)+pow(q->y-y,2));
}
float& Point3D::getZ(void)
{
return z;
}
float Point3D::KhoangCach(void* p)
{
Point3D* q = (Point3D*)(p);
return sqrt(pow(q->x-x,2)+pow(q->y-y,2)+pow(q->z-z,2));
}
int main()
{
Point2D v2;
Point2D u2;
cout<<".::-----Nhap toa do cho hai Point2D u va v-----::."<<endl;
cout<<"+ Toa do u:"<<endl;
cin>>v2.getX();
cin>>v2.getY();
cout<<"+ Toa do v:"<<endl;
cin>>u2.getX();
cin>>u2.getY();
Point* u = &v2;
Point* v = &u2;
cout<<"D(u,v) = "<<u->KhoangCach(v);
Point3D v3;
Point3D u3;
cout<<endl<<".::-----Nhap toa do cho hai Point3D u va v-----::."<<endl;
cout<<"+ Toa do u:"<<endl;
cin>>v3.getX();
cin>>v3.getY();
cin>>v3.getZ();
cout<<"+ Toa do v:"<<endl;
cin>>u3.getX();
cin>>u3.getY();
cin>>u3.getZ();
Point* p = &v3;
Point* q = &u3;
cout<<"D(u3,v3) = "<<p->KhoangCach(q);
cout<<endl;
return 0;
}
Phần tính khoảng cách của lớp Point2D và Point3D khó hiểu quá. Tại sao phải đặt Point2D *q=(Point2D*)(p)
để làm gì? q->x
: là x của tham số nào? Và -x
: là trừ x của tham số nào? Rối quá.
Mong được gỡ rối dùm.
Cảm ơn.
Bài liên quan
Điều khó hiểu hơn là vì sao không dùng reference đặt gạch
Chắc tại tác giả muốn dùng ví dụ này để áp dụng Lớp cơ sở trừu tượng.
Còn phần Reference thì trong sách tôi đang đọc vẫn chưa thấy nói tới.
Nhận xét:
Lớp Point3D còn chưa có constructor.
“constructor” thì tôi không rỏ, có phải ý của Dark.Hades là hàm tạo không?
Ở đây không dùng hàm tạo mà chương trình sẽ yêu cầu ta nhập vào các đặc trưng của đối tượng.
Thiếu
const
ở tham số.Thực ra dòng ép kiểu đó không cần thiết. Viết hẳn lên chỗ tham số luôn.
rogp10 muốn nói tham số của hàm nào thiếu
cosnt
? chương trình vẫn chạy đúng mà.Vì cái chương trình của bạn dùng quá nhiều tham chiếu (void), để làm gì thì mình không rõ, có lẽ tránh lỗi khi không may viết nhầm tham chiếu chăng??
Viết như vậy đến lúc tham chiếu nhầm giá trị mà cứ ép kiểu thì …
Nên xoá hết void, sử dụng nạp chồng hàm để chương trình rõ ràng
Các hàm get sẽ theo dạng:
getSomeThing() const
Hàm set sẽ theo dạng:
setSomeThing(const &ref)
Còn phần constructor mình nói phía trên là Point 3d sẽ có 3 chiều, tuy nhiên chương trình của bạn thì chỉ kế thừa lại Point2D mà không xây lại hàm nhập chiều Z
Xin cảm ơn những chia sẽ của các tiền bối.
Nhưng hiện tại tôi chỉ mới học được một vài thứ thôi nên những gợi ý thay đổi chương trình ở trên thì tôi lại càng không hiểu.
Có lẽ chương trình này chưa phải là tốt nhất để tính khoảng cách 2 điểm, nhưng nó dùng để minh họa cái lý thuyết mà tôi đang học là “Lớp cơ sở trừu tượng”.
Do không hiểu được ví dụ này nên tôi sẽ không thể sử dụng được nó (Lớp cơ sở trừu tượng) trong những trường hợp thật sự cần thiết.
Chương trình này đã chạy đúng rồi, nhờ tiền bối nào hiểu được thì giải thích dùm những thắt mắc của tôi ở trên.
Xin cảm ơn.
Nói sơ:
Phương thức virtual có tính chất khi gọi qua một ref của superclass thì phương thức của subclass luôn được gọi, chứ không phải superclass. Đây là nền tảng cho đa hình (gom nhiều đối tượng của subclass…)
Pure virtual (gán bằng 0 như trên) làm cho chính superclass không thể instantiate được, hay nó là trừu tượng do không thể có đối tượng của nó, kéo theo các subclass buộc phải override nó.
Khi một superclass có toàn pure virtual (gồm pure destructor) thì có thể xem là interface và không gặp vấn đề với multi inheritance.
Cảm ơn rogp10!
Góp ý trên giúp tôi hiểu được đơn giản hơn về các khái niệm. Lúc tự đọc thấy hơi mơ hồ.
Tôi vẫn chưa hiểu được cú pháp chi tiết của ví dụ trên. Nhờ các cao thủ chỉ bảo dùm.
virtual <prototype của phương thức yêu cầu override> = 0;
Vậy ta nên viết lại prototype như sau:
virtual KhoangCach(const Point &p) = 0;
Chú ý p này có kiểu là Point&.Để
void*
rất nguy hiểm vì cái gì cũng truyền vào được. Để cho chắc, bạn nên tìm hiểu vềdynamic_cast
.p/s: thực ra destructor nên cho
virtual
hết, vì khi đã cần viết destructor tức là phải free cái gì đó (rule of 3) nên destructor PHẢI được gọi đúng.VD: một class
Logging
giữ một file handle để ghi nhật trình (log). Resource được giữ là quyền exclusive writing lên file đó, nên áp dụng rule of 3. Giờ classLoggingMoar
th.kLogging
mở thêm cái file nữa thì sao