# Đề tài: [C++] Nạp chồng toán tử ntn?

1. ## [C++] Nạp chồng toán tử ntn?

Các bác vui lòng cho em hỏi:
- Em có viết một cái thư viện phân số dùng riêng cho bài tập mà em đang làm. Trong quá trình giải bài toán thì mọi số liệu được tính toán đều ở dạng phân số. Các bác cho em hỏi là, nếu bây giờ, em muốn thay thế cách gọi hàm congphso(Phanso a, Phanso b) chẳng hạn (tính tổng của 2 phân số a và b) bằng cách ký hiệu: a + b ??? thì ta làm thế nào ạ? Và tương tự cho các phép toán còn lại.

Xin lỗi các bác nếu em viết tiêu đề bài viết ko rõ ràng.  Trả lời cùng với trích dẫn

2. ý bạn nói là nạp chồng toán hạng phải không, ngày trước xem qua c++ thấy phần này không cần thiết nên bỏ luôn không thèm học,bây giờ chỉ nhớ mang máng là cái này "operator +" bạn học c++ chắc phải có tài liệu gì đấy, cứ theo hướng ấy mà nghiên cứu, c# cũng có cái này nhưng phải tuần sau mình mới học đến, bạn đã vi phạm đặt tiêu đề chung chung, mod ở đây là iamvtn nóng tính lắm , cẩn thận
Đã được chỉnh sửa lần cuối bởi tienlbhoc : 12-07-2007 lúc 10:35 AM.  Trả lời cùng với trích dẫn

3.  Thành viên mới Ngày gia nhập
04 2007
Bài viết
4
PhanSo operator x (PhanSo const & PS1, PhanSo const & PS2)
{
PhanSo Kq;
return Kq;
}
x là +,-,*,/,+=,-=,...  Trả lời cùng với trích dẫn

4.  XCoworker Member Ngày gia nhập
07 2006
Bài viết
166
http://www.cplusplus.com/doc/tutorial/classes2.html
Code:
```Classes (II)

Last update on Feb 2, 2007 at 9:21pm
C++ incorporates the option to use standard operators to perform operations with classes in addition to with fundamental types. For example:

int a, b, c;
a = b + c;

This is obviously valid code in C++, since the different variables of the addition are all fundamental types. Nevertheless, it is not so obvious that we could perform an operation similar to the following one:

struct {
string product;
float price;
} a, b, c;
a = b + c;

In fact, this will cause a compilation error, since we have not defined the behavior our class should have with addition operations. However, thanks to the C++ feature to overload operators, we can design classes able to perform operations using standard operators. Here is a list of all the operators that can be overloaded:

+    -    *    /    =    <    >    +=   -=   *=   /=   <<   >>
<<=  >>=  ==   !=   <=   >=   ++   --   %    &    ^    !    |
~    &=   ^=   |=   &&   ||   %=   []   ()   ,    ->*  ->   new
delete    new[]     delete[]

To overload an operator in order to use it with classes we declare operator functions, which are regular functions whose names are the operator keyword followed by the operator sign that we want to overload. The format is:

type operator sign (parameters) { /*...*/ }

Here you have an example that overloads the addition operator (+). We are going to create a class to store bidimensional vectors and then we are going to add two of them: a(3,1) and b(1,2). The addition of two bidimensional vectors is an operation as simple as adding the two x coordinates to obtain the resulting x coordinate and adding the two y coordinates to obtain the resulting y. In this case the result will be (3+1,1+2) = (4,3).

#include <iostream>
using namespace std;

class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator + (CVector);
};

CVector::CVector (int a, int b) {
x = a;
y = b;
}

CVector CVector::operator+ (CVector param) {
CVector temp;
temp.x = x + param.x;
temp.y = y + param.y;
return (temp);
}

int main () {
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
cout << c.x << "," << c.y;
return 0;
}

4,3

It may be a little confusing to see so many times the CVector identifier. But, consider that some of them refer to the class name (type) CVector and some others are functions with that name (constructors must have the same name as the class). Do not confuse them:

CVector (int, int);            // function name CVector (constructor)
CVector operator+ (CVector);   // function returns a CVector

The function operator+ of class CVector is the one that is in charge of overloading the addition operator (+). This function can be called either implicitly using the operator, or explicitly using the function name:

c = a + b;
c = a.operator+ (b);

Both expressions are equivalent.

Notice also that we have included the empty constructor (without parameters) and we have defined it with an empty block:

CVector () { };

This is necessary, since we have explicitly declared another constructor:

CVector (int, int);

And when we explicitly declare any constructor, with any number of parameters, the default constructor with no parameters that the compiler can declare automatically is not declared, so we need to declare it ourselves in order to be able to construct objects of this type without parameters. Otherwise, the declaration:

CVector c;

included in main() would not have been valid.

Anyway, I have to warn you that an empty block is a bad implementation for a constructor, since it does not fulfill the minimum functionality that is generally expected from a constructor, which is the initialization of all the member variables in its class. In our case this constructor leaves the variables x and y undefined. Therefore, a more advisable definition would have been something similar to this:

CVector () { x=0; y=0; };

which in order to simplify and show only the point of the code I have not included in the example.

As well as a class includes a default constructor and a copy constructor even if they are not declared, it also includes a default definition for the assignment operator (=) with the class itself as parameter. The behavior which is defined by default is to copy the whole content of the data members of the object passed as argument (the one at the right side of the sign) to the one at the left side:

CVector d (2,3);
CVector e;
e = d;           // copy assignment operator

The copy assignment operator function is the only operator member function implemented by default. Of course, you can redefine it to any other functionality that you want, like for example, copy only certain class members or perform additional initialization procedures.

The overload of operators does not force its operation to bear a relation to the mathematical or usual meaning of the operator, although it is recommended. For example, the code may not be very intuitive if you use operator + to subtract two classes or operator== to fill with zeros a class, although it is perfectly possible to do so.

Although the prototype of a function operator+ can seem obvious since it takes what is at the right side of the operator as the parameter for the operator member function of the object at its left side, other operators may not be so obvious. Here you have a table with a summary on how the different operator functions have to be declared (replace @ by the operator in each case):

Expression	Operator	Member function	Global function
@a	+ - * & ! ~ ++ --	A::operator@()	operator@(A)
a@	++ --	A::operator@(int)	operator@(A,int)
a@b	+ - * / % ^ & | < > == != <= >= << >> && || ,	A::operator@ (B)	operator@(A,B)
a@b	= += -= *= /= %= ^= &= |= <<= >>= []	A::operator@ (B)	-
a(b, c...)	()	A::operator() (B, C...)	-
a->x	->	A::operator->()	-
Where a is an object of class A, b is an object of class B and c is an object of class C.

You can see in this panel that there are two ways to overload some class operators: as a member function and as a global function. Its use is indistinct, nevertheless I remind you that functions that are not members of a class cannot access the private or protected members of that class unless the global function is its friend (friendship is explained later).

The keyword this
The keyword this represents a pointer to the object whose member function is being executed. It is a pointer to the object itself.

One of its uses can to check if a parameter passed to a member function is the object itself. For example,

// this
#include <iostream>
using namespace std;

class CDummy {
public:
int isitme (CDummy& param);
};

int CDummy::isitme (CDummy& param)
{
if (&param == this) return true;
else return false;
}

int main () {
CDummy a;
CDummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b";
return 0;
}

yes, &a is b

It is also frequently used in operator= member functions that return objects by reference (avoiding the use of temporary objects). Following with the vector's examples seen before we could have written an operator= function similar to this one:

CVector& CVector::operator= (const CVector& param)
{
x=param.x;
y=param.y;
return *this;
}

In fact this function is very similar to the code that the compiler generates implicitly for this class if we do not include an operator= member function to copy objects of this class.

Static members
A class can contain static members, either data or functions.

Static data members of a class are also known as "class variables", because there is only one unique value for all the objects of that same class. Their content is not different from one object of this class to another.

For example, it may be used for a variable within a class that can contain a counter with the number of objects of that class that have been created, as in the following example:

// static members in classes
#include <iostream>
using namespace std;

class CDummy {
public:
static int n;
CDummy () { n++; };
~CDummy () { n--; };
};

int CDummy::n=0;

int main () {
CDummy a;
CDummy b;
CDummy * c = new CDummy;
cout << a.n << endl;
delete c;
cout << CDummy::n << endl;
return 0;
}

7
6

In fact, static members have the same properties as global variables but they enjoy class scope. For that reason, and to avoid them to be declared several times, we can only include the prototype (its declaration) in the class declaration but not its definition (its initialization). In order to initialize a static data-member we must include a formal definition outside the class, in the global scope, as in the previous example:

int CDummy::n=0;

Because it is a unique variable value for all the objects of the same class, it can be referred to as a member of any object of that class or even directly by the class name (of course this is only valid for static members):

cout << a.n;
cout << CDummy::n;

These two calls included in the previous example are referring to the same variable: the static variable n within class CDummy shared by all objects of this class.

Once again, I remind you that in fact it is a global variable. The only difference is its name and possible access restrictions outside its class.

Just as we may include static data within a class, we can also include static functions. They represent the same: they are global functions that are called as if they were object members of a given class. They can only refer to static data, in no case to non-static members of the class, as well as they do not allow the use of the keyword this, since it makes reference to an object pointer and these functions in fact are not members of any object but direct members of the class.```
Đã được chỉnh sửa lần cuối bởi vinhie47 : 12-07-2007 lúc 02:33 PM.  Trả lời cùng với trích dẫn

5.  Thành viên mới Ngày gia nhập
02 2007
Bài viết
27
Đối với cách viết thông thường, chúng ta viết thế này:

PS congPS(PS a,PS b)
{
PS c;
c.tu= a.tu*b.mau + a.mau*b.tu;
c.mau=a.mau*b.mau;
return c;

}
Và khi sử dụng thì viết: c=congPS(a,b);
Đúng không nè?

Đó là cách viết của C lập trình cấu trúc, muốn thực hiện "tham vọng" của bạn thì phải viết theo kiểu của C++ lập trình hướng đối tượng. Cách viết thế này:
PS operator+(PS a,PS b)
{
PS c;
c.tu= a.tu*b.mau + a.mau*b.tu;
c.mau=a.mau*b.mau;
return c;

}
Chỉ khác nhau cái dòng đầu tiên thôi, còn nội dung không khác. Và muốn chạy được hàm này, file nguồn của bạn phải save với đuôi là .CPP, nếu dùng đuôi .C thì sẽ báo lỗi.
Muốn cộng 2 phân số a,b thì viết c=a+b như bình thường, còn muốn cộng 2 số nguyên a,b cũng viết c=a+b, trình biên dịch sẽ tự hiểu.

Đối với những toán tử khác thì cũng tương tự, ví dụ những toán tử sau: -(tính hiệu), *, /, %, ^, ++, --, -(số đối, ví dụ a=-a),...

Cách này gọi là nạp chồng toán tử (operator overloading) nghĩa là thêm chức năng cho toán tử. Sau này học lên C++ bạn sẽ hiểu thêm, còn bây giờ thì tham khảo cho vui cũng được.

GOOD LUCK!  Trả lời cùng với trích dẫn

6. ## [C++] Nạp chồng toán tử ntn?

Cảm ơn anh hirikarate đã giúp so_0. Nhưng mà anh ạ, lại có vấn dề là khi em thay thế Phanso congphso(Phanso a, Phanso b) bằng Phanso operator + (Phanso a, Phanso b) thì nó báo lỗi:
struct Phanso __cdecl operator+(struct Phanso,struct Phanso)" (??H@YA?AUPhanso@@U0@0@Z)
khi em chạy thử bằng cách gọi c = a + b. Mong các đàn anh giúp tiếp ạ.

so_0 mới chỉ học ở mức lập trình cấu trúc, nhưng mà vì đang làm cái bài tập về môn quy hoạch toán - giải bài toán bằng đơn hình đối ngẫu và so_0 có "tham vọng" đưa dữ liệu tính toán sang dạng phân số để có kết quả với độ chính xác cao hơn (khi đầu vào là số nguyên), nên mới "tham vọng" về chuyện "nạp chồng toán tử" vốn lạ lẫm... Mong các đàn anh chỉ giáo thêm.  Trả lời cùng với trích dẫn

7. Khoan so_0 nè . Cậu dùng struct sao được .
Cậu thay thế như sau thì được nè :
vd của cậu là:
struct PhanSo
{
...........
PhanSo CongPhanSo(-----);
}
thay lại thế này :
class PhanSo
{
public:
................
PhanSo operator+(PhanSo A,PhanSo B)
{---}
}

Rồi như thế là ok .
* Cậu đặt cái tiêu đề rõ rõ , mọi người thấy nó mơ hồ quá nên không vào .  Trả lời cùng với trích dẫn

8. Các đàn anh có thể cho so_0 hỏi là: ta phải khai báo thế nào để có thể nạp chồng toán tử nhỏ hơn "<" khi cần so sánh phân số a với 0, hay là chỉ nên so sánh "gián tiếp" a.tuso với 0 là đủ???  Trả lời cùng với trích dẫn

9. Tùy thôi , nhưng mà nếu đơn giản thì cứ "gián tiếp" như cậu hiểu đi . Khi nào học đến C++ thì thử lại cũng ko muộn mà .  Trả lời cùng với trích dẫn

10. Nguyên bản được gửi bởi so_0 Các đàn anh có thể cho so_0 hỏi là: ta phải khai báo thế nào để có thể nạp chồng toán tử nhỏ hơn "<" khi cần so sánh phân số a với 0, hay là chỉ nên so sánh "gián tiếp" a.tuso với 0 là đủ???
a.tuso với 0 là chưa đủ vì ví dụ như a.tuso < 0 nhưng a.mauso<0 => a > 0  Trả lời cùng với trích dẫn

#### Quyền hạn của bạn

• Bạn không thể gửi đề tài mới
• Bạn không thể gửi bài trả lời
• Bạn không thể gửi các đính kèm
• Bạn không thể chỉnh sửa bài viết của bạn