01/10/2018, 11:06
Thắc mắc: Class và hướng đối tượng trong C++
Em đang tự học C++, hiện tại đang làm bài tập viết class cộng hai phân số ạ. em viết thì đã hiển thị đúng kết quả, nhưng code thì em nghĩ là mình dùng sai cách hoặc chưa thực hiện đúng tiêu chí hướng đối tượng. Vì thế, em đăng lên đây nhờ các anh các chị chỉ giáo giúp em tìm khuyết điểm trong code của mình ạ. Em xin chân thành cảm ơn
#include <iostream>
using namespace std;
class PhanSo{
private:
int _ts;
int _ms;
public:
void nhap();
void xuat();
void rutGon(PhanSo &ps);
void cong(PhanSo ps1, PhanSo ps2);
};
void PhanSo::nhap(){
cout << "Nhap tu so: ";
cin >> this->_ts;
cout << "Nhap mau so: ";
cin >> this->_ms;
}
void PhanSo::xuat(){
cout << this->_ts << "/" << this->_ms;
}
void PhanSo::rutGon(PhanSo &ps){
int a = ps._ts;
int b = ps._ms;
while (a != b){
if (a > b) a -= b;
else b -= a;
}
ps._ts = ps._ts / a;
ps._ms = ps._ms / a;
}
void PhanSo::cong(PhanSo ps1, PhanSo ps2){
PhanSo tong;
tong._ts = ps1._ts*ps2._ms + ps2._ts*ps1._ms;
tong._ms = ps1._ms * ps2._ms;
cout << tong._ts << "/" << tong._ms;
}
int main(){
PhanSo ps1, ps2;
ps1.nhap();
ps2.nhap();
ps1.rutGon(ps1);
ps2.rutGon(ps2);
ps1.cong(ps1, ps2);
system("pause");
return 0;
}
Bài liên quan
@ltd anh Đạt giúp em với ạ
rutgon
nên dùng % thay vì -= (tất nhiên là phải sửa :v)cong
này không kiểm tra tràn số và không rút gọn.Vâng, đúng là hàm cộng không thể rút gọn được phân số ạ
Mà kiểm soát dữ liệu không có là như nào anh, thuộc mảng kiến thức nào ạ? Anh có thể chỉ rõ hơn cho em được ko?
Tại sao không được?
Mẫu phải khác 0 và nếu mẫu là số âm thì phải chỉnh lại.
Cộng thì nên khai báo là operator để có thể viết được phép tính như sau :
Mình đoán là cái hàm rút gọn kia không chạy đúng với số âm
Ngoài ra phép cộng không tính mẫu nhỏ nhất có thể, nên một số phép cộng sẽ khó khăn hơn. Nên tách phần ucln thành helper.
Theo như mình thấy, bạn làm thế cũng đúng yêu cầu đề bài, tuy nhiên tư duy thì hơi ngắn, hoặc là do em mới chỉ biết 1 hình thức khai báo của phương thức/hàm.
rutGon
là phương thức của đối tượng. Giả sử em có 2 đối tượng phân sốps1
vàps2
, em gọi phương thứcps1.rutGon(ps2)
thì nó sẽ rút gọnps2
, em thấy có buồn cười khôngCách giải quyết là viết phương thức tác động trực tiếp lên đối tượng
this
(anh viết rút gọn, không cóthis
nhé), đồng thời thay đổi thuật toán để rút gọn cả phân số âm:Như vậy, khi muốn rút gọn phân số
ps69
, ta chỉ việcps69.rutGon();
thậm chí nếu gọi phương thức bằng các phương thức của chính đối tượng đó thì chỉ cầnrutGon();
nhap
của em nó rất ư là có vấn đề vì không kiểm tra điều kiện. Cái này là tối kỵ nhé.xuat
của em nên viết riêng cho trường hợp giá trị của phân số là số nguyên.cong
của em chưa rút gọn phân số.cong
, em phải tư duy khác một chút: Bởi vì phép cộng của 2 phân số sẽ cho kết quả là 1 phân số, thế nên em nên trả về kiểu dữ liệuPhanSo
thay vì kiểu dữ liệuvoid
Nếu là anh, anh sẽ viết chương trình phức tạp hơn 1 chút như sau (Vì anh viết phương thức
cong
trả về kiểu dữ liệuPhanSo
nên anh viết hàm đó nằm ở ngoài class. Vì hàm nằm ở ngoài class thì không truy cập được vào các thuộc tínhprivate
nên anh viết thêm phương thứcGet
):À lộn, trong C++ thì
this
là con trỏ, không phải đối tượngHi Nguyen Dinh Dung.
Góp ý thêm.
VIết hết các toán tử mà phân số có thể dùng.
Thêm phương thức lấy giá trị tử số mẫu số.
Toán tử ép kiểu về float hoặc doble.
Đổi dấu trước khi chạy thuật toán Euclid là xong rồi @@ đâu cần phải chia làm gì.
Kèm theo khống chế mẫu luôn dương thì chỉ thêm 1 dòng.
Theo mình thì dấu của phân số không phải là dấu của tử số hay mẫu số. Vậy nên kiểu dữ liệu của tử số và mẫu số là số nguyên không đấu mẫu khác 0 và thêm một thuộc tính dấu cho phân số nữa.
Rational number
In mathematics, a rational number is any number that can be expressed as the quotient or fraction p/q of two integers, a numerator p and a non-zero denominator q. Since q may be equal to 1, every integer is a rational number. The set of all rational numbers, often referred to as "the rationals", the field of rationals or the field of rational numbers is usually denoted by a boldface Q (or blackboard bold Q {\displaystyle \mathbb {Q} Th...
Việc tách dấu lưu riêng không thật sự cần thiết, vì dung lượng sẽ đội lên mà hiệu quả không có.
Em cảm ơn các anh, em sẽ nghiền ngẫm lại comment của các anh và học thêm phần kiến thức còn thiếu ạ. Thanks!!!
Vấn đề là mục đích của mình không phải là tìm UCLN mà là rút gọn phân số, kiểu gì cũng phải dùng thêm một vài biến trung gian để lưu dấu phép tính, các biến tạm để tìm UCLN, tốc độ cải thiện không đáng kể nhưng code sẽ phức tạp hơn 1 chút, trong khi thuật toán của mình nó tường minh hơn. Nếu muốn code bằng Euclid mà sáng sủa thì phải xây riêng 1 hàm tính UCLN.
Còn nếu bạn nào thấy vụ
abs...
phức tạp thì choi ≤ min(abs(TuSo), abs(MauSo))
cũng không vấn đề gì.Hi rogp10.
Thực ra kiểu dữ liệu không dấu và kiểu dữ liệu có dấu tốn dung lượng như nhau, 1 đằng thì từ
0 - 2 ^ n
đến2 ^ n - 1
, một đằng thì từ0
đến2 ^ 2n - 1
, dùng bao nhiều thì xài bấy nhiêu thôi. Chưa kể bây giờ nếu muốn làm triệt để thì người ta có BigInteger rồi, số càng to càng tốn bộ nhớ.Nhưng mà nếu thêm 1 biến dấu thì đúng là nó phức tạp hơn vì phải có thêm các thao tác kiểm dấu trong bất kỳ phép tính nào, thiếu đi sự tự nhiên của phép tính.
Vấn đề (-2/3 và 2/-3) hay (1/2 và 2/4) thì giải quyết như em ở trên, phương thức rút gọn được đưa vào constructor. Và như vậy thì ngay cả việc xét dấu cũng chỉ cần xét tử số.
Thuật toán bạn đưa ra là O(n), với mẫu số đủ lớn thì chả biết chừng nào xong (gcd cỡ tỉ -> 5-6 tỉ bước, khoảng 2s), trong khi Euclid nháy mắt xong. (hàng log(n))
Vậy bạn tính lưu dấu ở đâu? Có phải là đội dung lượng mà không ích lợi gì không?
Hi rogp10.
VD. Mình dùng 3 biếnt int không dấu đề lưu một phân số nhưng có miền giá trị là lớn gấp đôi bạn dùng 2 biến int.
Vẫn không đáng. Lấy thêm 1 byte của bạn nữa là được hẳn 63 bit rồi.