Toán tử mũi tên. Các đối tượng nhập xuất

1. Cho mình hỏi. Mình có 1 class

Circle
{
    double Radius;
public:
    void Set( double x0, double y0, double r);
    double Area();
};

và đoạn code này

void main()
{
    Circle* mycir;
    mycir->Set(20, 20, 100);
    double mArea = mycir->Area();
}

Tại sao ở đó dùng toán tử mũi tên mà không dùng toán tử chấm. Nó có khác nhau gì, ưu tiên gì không ạ?

mycir.Set(20,20,100);
double mArea = mycir.Area();

2.
Các hàm nhập xuất kiểu như

void inputCircleData(istream& inDevice, Circle& cir)
{
    double X0, Y0, r;
    inDevice >> X0 >> Y0 >> r;
    cir.Set(X0,Y0,r);
}

Khi gọi hàm trong main thì sẽ gọi dòng inputCircleData(cin, mycir);

Theo em hiểu thì nó thay inDevice bằng cin và định dạng nhập xuất chuẩn thông thường từ bàn phim, tương tự cout.

Nhưng với hàm dùng operator

istream& operator >> (istream& inDevice, Circle& cir)
{
    double X0, Y0, r;
    inDevice >> X0 >> Y0 >> r;
    cir.Set(X0,Y0,r);
    return inDevice;
}

khi gọi hàm lại chỉ là cin >> mycir;
Em chưa hiểu lắm về cái hàm đó, ai có thể giải thích cho em đc không.

Em cảm ơn.


Câu trả lời được chấp nhận:

1 Like

đối tượng là con trỏ thì dùng “->” , đối tượng bình thường mới dùng “.” nhé

 Circle * mycir;
mycir->Set();
3 Likes

do bạn khai báo mycir là một con trỏ, nên khi bạn cần truy cập đến Set thì phải dùng ->

1 Like

Mà tại sao mình không khai báo biến bình thường luôn nhỉ. Mình có đọc qua ở đâu đó là ở LT hướng đối tượng chỉ có C++ có cơ chế riêng làm trực tiếp được, với đa số ngôn ngữ khác thì phải làm dài dòng, tường minh hơn gì đó?
Giống như

Circle* mycir; //chưa có đối tượng
mycir = new Circle();
mycir->Set();

thay vì C++ có thể

Circle mycir; //tự động tạo
mycir.Set();

phải là

mycir = new Circle;

chứ

cái này e ko hiểu a @ltd ơi, a làm cái topic về operator trong C++ đi a. TT.TT

Mình cũng thấy lạ chỗ đó nhưng mà giáo trình ghi thế

1 Like

à, chắc là hàm tạo không có tham số.

Theo mình nhớ thì con trỏ tốn ít bộ nhớ hơn

1 Like

Em nghĩ cũng bao nhiêu đó mà nhỉ ^^ dù gì cũng hủy bộ nhớ được cấp phát sau khi chương trình dừng lại

con trỏ chỉ dùng có 4 byte thôi (mình nhớ là vậy), trong khi khai báo biến thì phải dùng 128, lâu rồi không đụng tới HDT nên không nhớ lắm, bác thử khai báo 2 biến, 1 biến con trỏ và 1 biến bình thương rồi sizeof nó ra thử xem

1 Like
SDonThuc* contro;
contro = new SDonThuc;
SDonThuc bthuong;
cout << sizeof(contro) << " " << sizeof(bthuong);

Em thử thế này thì ra 4 với 12 thật ^^

QuanLySanXuat*x = new QuanLySanXuat;
QuanLySanXuat a;
cout << "size pointer: " << sizeof(x) << endl;
cout << "size var : " << sizeof(a) << endl;

Ví dụ đoạn code bên trên thì mình có 1 class quản lý sản xuất, class này quản lý 4 cái class nhỏ, class này mình chạy ra thì pointer chỉ cố định là 4, nhưng var thì lên tới 88

1 Like

Khi đối tượng mình đang sử dụng là con trỏ, thì mình phải dùng -> để gọi các phương thức, thành viên con của nó. Khi đối tượng của mình không phải là con trỏ, thì mình dùng . để gọi các phương thức, thành viên của nó.

Lưu ý thêm một điều là trong định nghĩa class của @genius_hcmus còn thiếu hàm dựng, và khi tạo con trỏ ra thì mình phải khởi tạo cho nó nữa chứ.

Phải như thế này

Circle* mycir = new Circle();

Hoặc như thế này

Circle* mycir = new Circle;

@htwap theo anh đọc và kiểm tra thử thì 2 cách này là tương đương nhau trong trường hợp hàm dựng không có tham số.

Đó là vì ta đã “định nghĩa lại” operator >> đối với class mình đang nói tới Circle. Ta có thể hình dung như thế này. Khi ta cin một biến kiểu int hoặc float thì giá trị được nhập vào biến đó rất dễ dàng. Bởi vì các kiểu dữ liệu đó là kiểu dữ liệu “cơ bản”.

Tuy nhiên, với kểu dữ liệu tự định nghĩa. Tức là @genius_hcmus tự dịnh nghĩa lại cấu trúc của kiểu dữ liệu đó. Khi này, hàm cin không biết được dụng ý của mình trong cách lưu trữ cấu trúc mới này. Để có thể “tận dụng” được istream cin và truyền dữ liệu vào cấu trúc mới, mình cần phải “định nghĩa” lại hành vi >> cho kiểu dữ liệu Circle này.

Đoạn code này nhằm định nghĩa lại thao tác >> đối với kiểu dữ liệu Circle.

istream& operator >> (istream& inDevice, Circle& cir)
{
    double X0, Y0, r;
    inDevice >> X0 >> Y0 >> r;
    cir.Set(X0,Y0,r);
    return inDevice;
}

Nhờ có nó nên sau này ta chỉ cần cin >> mycir; là đủ.

2 Likes

Thế mình dùng con trỏ để cho đỡ tốn bộ nhớ à anh, em nhớ em đọc hình như chỉ có C++ mới đc dùng trực tiếp biến bình thường như cách này thôi. Đa số ngôn ngữ OOP khác đều phải làm tuần tự bằng con trỏ?

Circle mycir; //tự động tạo
mycir.Set();
mycir.Set(20,20,100);
double mArea = mycir.Area();

Con trỏ là một cách khác để truy xuất đến một vùng nhớ, dùng con trỏ không phải để tiết kiệm bộ nhớ.

Câu này phải nói ngược lại mới đúng. Chỉ có C++ mới có con trỏ, các ngôn ngữ hướng đối tượng khác thì không.

2 Likes

Nếu vậy hai cách trên nếu dùng ngôn ngữ khác thì mình phải dùng cách khai báo biến thường rồi dùng toán tử . thôi hả anh?
Còn cái operator em hiểu rồi ^^ thì ra hàm định nghĩa lại operator insertion này >>

Mỗi ngôn ngữ có một cấu trúc khác nhau, nhưng đúng, các ngôn ngữ khác họ thường dùng .

1 Like

Cảm ơn a Đạt và mọi người nhiều nha

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?