Xin chỉ bảo về struct và class

Chào các bác, Em đang học c++ tới phần linked list và em đọc hướng dẫn không hiểu, mong các bác giải thích giúp em với ạ.
Thứ nhất khi nào thì gọi tên struct trong chính nó ạ (em không biết diễn đạt ra sao các bác xem qua ví dụ giúp em ạ.)

struct Node {
// Instance variables
const char* element;
Node* next;

// Initialize a node
Node(const char* e = NULL, Node* n = NULL)// tại sao ở đây lạ gọi tên chính nó ạ ?
{
element = e;
next = n;
}
};

Hay như ví dụ sau trên stdio

struct SNode
{
    int Data;
    SNode* pNext;
};

struct SList
{
    SNode* pHead;
    SNode* pTail;

    SList(){}// tại sao ở đây cũng gọi tên chính nó và không truyền vào gì ?
    SList(SNode* Head, SNode* Tail)// và ở đây lại truyền vào tham số mà không phải câu lệnh bên trên ạ ?
    {
	    this->pHead = Head;
	    this->pTail = Tail;
    }
};

Các bác có thể giải thích kĩ cho em cái này được không ạ ? tại sao trong class hay struct lại có những hàm tên là chính tên của class hay struct đó ạ ? Hoặc các bác có thể cho em xin tài liệu phần này em đọc được không ạ ? em tìm mà không có. Và trước đây em chỉ được học khởi tạọ 1 struct bằng cách

[tenstruct].[phantu] = value;

nhưng có lần em đọc có thể khởi tạo bằng cách ví dụ có 1 struct hocsinh trong đó có hoten và tuôi thì có thể khởi tạo là hocsinh1(“nguyen”, 20); hay gì đó đại loại vậy, em không biết nó là sao ai có thể cho em hướng dẫn được không ạ ? em cảm ơn mọi người !

1 Like

Bấm lộn sửa post :’(
Cái này là phương thức khởi tạo
Cái SList(){} không truyền gì vào thì nó là khởi tạo rỗng
Còn SList(SNode* Head, SNode* Tail) có truyền tham số thì lúc gọi ở hàm main bạn truyền biến Node vào nó sẽ khởi tạo giá trị cho struct SList

2 Likes

Em vẫn không hiểu cái gọi tên trong nó lắm ạ. Bác cho em xin 1 ví dụ đơn giản được không ạ ?

Bạn có thể tạo một biến có kiểu là con trỏ trỏ tới struct X trong struct X. Đó là nhờ sự ma thuật của một thứ được gọi là

Tính đa hình <(")

Tuy nhiên nếu bạn làm ntn:

struct Node {
 Node abc;
}

là bị compiler nó chửi liền. Vì khi đó là đúng như bạn nghĩ là nó sẽ bị lặp vô hạn. Nhưng khi như thế này

struct Node {
 Node* abc; // lưu ý dấu *
}

thì lại được là do khi đó Node * được xem như làm một con trỏ bình thường chứ không phải là một struct Node. Mà một con trỏ thì sẽ được tự động compiler cấp phát cho số bytes đúng với số bytes để lưu trữ một địa chỉ ô nhớ. Cụ thể là ở HDH 64bit bạn sẽ đc cấp phát 8 bytes và 32bit là 4 bytes.

Khi đó code được xem như này nè

struct Node {
 void * abc;
}

Tuy nhiên tại sao con trỏ lại trỏ tới cái Node được trong khi tui đang khai báo nó mà? :thinking:
Đây là phép màu của con trỏ. Con trỏ có một thuộc tính trong OOP được gọi là tính đa hình.
Vì sao nó lại có đa hình? Vì con trỏ méo quan tâm nó đang trỏ tới dữ liệu nào cả. Cái nó chỉ quan tâm là nó đang trỏ tới đâu. Việc nặn hình dữ liệu ra sao thì do lập trình viên nặn ra và hỗ trợ một chút từ compiler.

Ví dụ luôn cho nóng.

int a = 0x12345678; // ở hệ 10 là 305419896
void *ptrA = &a; // con trỏ trỏ tới địa chỉ của a
 // magic đây, bây giờ mình sẽ kêu con trỏ xem dữ liệu đang trỏ tới là một mảng kiểu byte
char * byteA = (char *)ptrA;
for(int i = 0; i < 4; i++) {
 printf("%x\n", byteA[i]); // in ra 0x12, 0x34, 0x56, 0x78
}

Thì ở cái snippet trên là một cách bạn chuyển đổi một kiểu int thành một mảng byte (vì c ko có byte nên xài tạm char) nhờ tính đa hình của con trỏ. Và bạn có thể thấy rằng, con trỏ thực sự ko quan tâm nó trỏ tới kiểu dữ liệu nào, mà chỉ quan tâm nó trỏ tới đâu. Nên bạn rất dễ dàng tùy chỉnh nó theo ý mình. Nhờ đó, bạn có thể cho nó trỏ tới một biến kiểu Node và truy cập mọi phần tử trong Node rất dễ dàng.

Và phần này cũng không dễ hiểu vì nó râu ria nhiều phần khác nữa. Nên bạn ráng chấp nhận nó trước. Rồi từ từ khám phá sau cũng không muộn đâu :3

Còn cái khởi tạo kiểu dữ liệu kiểu khác thì bạn Rerosu có gợi ý cho bạn rồi đó. Bạn tìm hiểu về Constructor nha.

9 Likes

Mình Cảm ơn nhiều lắm ạ !! về cơ bản cái tự gọi nó mình đã tương đối hiểu rồi ạ. Còn cụ thể vào phần linked list có thể giải thích cho mình hiểu đoạn code này không ạ ?

Node(const char* e = NULL, Node* n = NULL)// tại sao lại phải khai báo 2 con trỏ truyền vào ạ ?
{
    element = e;
    next = n;
}

tại sao lại không viết là

Node()
{
    element = NULL;
    next = NULL;
}

và tưởng tự ở đoạn code bên dưới, tại sao lại phải có

SList(){}

trước

SList(SNode* Head, SNode* Tail)

bỏ đi có sao không ? à còn nữa cho mình xin tài liệu hay hướng dẫn gì về con trỏ this không ạ ?
Mình xin lỗi nếu câu hỏi nó có hơi củ chuối, nhưng giờ chẳng biết hỏi ai cả @@ google thì ra những cái vô cùng khó hiểu khác nữa. Cho mình xin Cảm ơn trước ạ !!

*edit 1 :À lại xin xỏ nữa ạ. Bác có tài liệu nào cực dễ hiểu về linked list không ạ ? cho mình xin với ! cái này học xong đầu óc cứ mơ màng, không biết đâu vào đâu. chỗ nào con trỏ chỗ nào giá trị, chỗ nào cấp phát rồi chỗ nào trỏ tới đâu nữa. cái duy nhất mình hiểu về linked list này là 1 node gồm 2 phần data và pointer. và các node liên kết với nhau bằng pointer. còn về phần code mình hoàn toàn mù tịt, tìm hiểu mấy hôm nay rồi ra toàn những thứ rất khó hiểu, một số người còn viết nó bằng class và nó càng khó hiểu hơn nữa.

  • Trong C++ class/struct có hàm đặc biệt là gọi là constructor sẽ được dùng để khởi tạo một đối tượng lúc ban đầu. Một constructor sẽ có tên giống như lớp và nó không có bất kỳ kiểu trả về, kể cả kiểu void.
    Như vấn đề mà bạn đang thắc mắc liên quan tới tính đa hình trong C++. Họ viết như vậy là để tăng tính linh hoạt khi khởi tạo một Node (xem ví dụ bên dưới). Bạn có thể viết đồng thời hai hàm như vậy trong struct Node của bạn.
#include <iostream>
struct Node {
    // Member variables
    const char* element;
    Node* next;
    //COnstructor không cần truyền giá trị chởi tạo cho  member variables mà  thực hiện khởi tạo ngay trong hàm 
    Node()
    {
        element = NULL;
        next = NULL;
    } 
    // Constructor có truyền giá trị khởi tạo cho  class , giá trị chởi tạo có thể thay đổi tùy ý 
    Node(const char* e, Node* n)
    {
        element = e;
        next = n;
    }

};

int main()
{
    Node a = Node("Hello", NULL);
    Node b = Node();
    std::cout <<"a.element=" << a.element << std::endl;
    std::cout <<"b.element=" << b.element << std::endl;
    return 0;
}

Vẫn như ý mình trả lời bên trên, bỏ đi không sao cả.

http://www.learn-c.org/en/Linked_lists

2 Likes

Cả hai gọi là tham số mặc định :slight_smile: hai đoạn mã khác nhau hẳn, vì đoạn trên cho gán từ bên ngoài (khác NULL). Có thể thấy rằng tham số dữ liệu được xem là chính, vì bạn ko thể bỏ qua nó mà khởi tạo cho next được.

3 Likes

Hi Idol.
Không chắc cái đó có thể gọi là đa hình không.

1 Like

Có lẽ vậy. Với đa hình bạn không cần biết đối tượng là lớp con nào :smiley: còn con trỏ mà deref không đúng kiểu thì văng.

1 Like

viết hay =)) lắm man

Cảm ơn mọi người ạ, mặc dù em vẫn rất là mông lung khó hiểu @@ nó triều tượng kiểu gì ý. Lúc thì trỏ tới NULL, lúc thì không… Cảm ơn mọi người đã tân tình giải thích ạ !!

Vì bạn bị đánh lạc hướng bởi OOP :slight_smile: nên quay trở lại thao tác (về mặt khái niệm - ADT) của DSLK trước chứ nhảy vào xem code thì phần sau còn rối hơn :smiley: Nắm được rồi thì có thể học một số chủ điểm của OOP 101.

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