2014-10-23 23 views
9

Tôi mới đến C++ và có một câu hỏi:Tạo một thể hiện của một lớp trong lớp tự

Hãy so sánh đoạn mã sau:

class Node { 
public: 
    int data; 
    Node* x; 
}; 

class Node { 
public: 
    int data; 
    Node x; 
}; 

Tôi biết thứ hai một phần của mã không thể vượt qua biên dịch. Nhưng tôi muốn biết lý do.

Có liên quan đến phân bổ bộ nhớ hoặc quy định cú pháp không?

Tôi sẽ đánh giá cao nếu ai đó có thể giải quyết câu hỏi của tôi.

+0

Trình biên dịch không phải biết enything trên nút để có thể quản lý con trỏ đến nút. – Caduchon

+0

Đó là ít nhất một phần liên quan đến cấp phát bộ nhớ, vì kích thước của cá thể 'Node' sẽ chuyển sang vô cùng vì đệ quy. Mỗi Instance sẽ chứa tất cả các biến của 'Node' cộng với một thể hiện khác của' Node', nó sẽ chứa một Instance khác và vân vân. Cuối cùng, cấu trúc không thể được cấp phát vì kích thước của nó là vô hạn. – antipattern

+0

Nhưng làm thế nào về một con trỏ? Tôi nghĩ rằng trường hợp đầu tiên có thể vượt qua biên dịch và hoạt động chính xác. – Oh2

Trả lời

12

Mã trong đoạn thứ hai của bạn không thể biên dịch được, vì lớp Node không được xác định hoàn toàn tại thời điểm bạn khai báo thành viên dữ liệu x của loại Node.

Vì lợi ích của sự hiểu biết, hãy tưởng tượng nếu nó có thể biên dịch, nó sẽ dẫn đến một số loại "cấu trúc đệ quy vô hạn", sẽ mất một lượng bộ nhớ vô hạn. Dưới đây là cách bố trí giả của một đối tượng lớp như:

{ 
    data: int 
    x: Node 
    { 
    data: int 
    x: Node 
    { 
     data: int 
     x: Node 
     { 
     ... 
     } 
    } 
    } 
} 

Các trường hợp đầu tiên làm việc bởi vì bạn không cần một lớp học để được xác định đầy đủ để khai báo một con trỏ đến nó.
Tôi thấy rằng suy nghĩ của "hoàn toàn xác định" là "trình biên dịch biết lớp lớn này" giúp lý do về các vấn đề như thế này: trình biên dịch cần biết lớp lớn là khai báo một cá thể của nó, nhưng không khai báo một con trỏ đến nó, có cùng kích thước bất kể lớp đó.

+0

Nhưng làm thế nào về một con trỏ? Tôi nghĩ rằng trường hợp đầu tiên có thể vượt qua biên dịch và hoạt động chính xác. – Oh2

+0

Câu trả lời đã chỉnh sửa để giải thích lý do tại sao nó hoạt động với một con trỏ –

+0

Bạn không cần phải biết kích thước của một đối tượng để tạo con trỏ đến nó, nó chỉ là một địa chỉ và nó không "chứa" anyting. – Dettorer

7

Nó liên quan nhiều hơn đến logic cơ bản. Để cho Node chứa một đối tượng có cùng kích thước với chính nó và một thứ khác, nó sẽ phải lớn hơn chính nó hoặc kích thước vô hạn.

Ngôn ngữ cũng ngăn không cho nó vì loại không đầy đủ trong định nghĩa riêng của nó (vì vậy bạn thậm chí không thể có trường hợp thoái hóa của một lớp trống khác có chứa chính nó). Nhưng điều đó khá ngẫu nhiên đối với sự bất khả thi logic cơ bản hơn.

14

Nếu bạn có thể, sau đó một Node sẽ chứa một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node , trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, trong đó có một Node, tiếp theo ains a Node, có chứa Node, có chứa Node ... và cứ thế cho đến khi vũ trụ đầy Nodes và implodes.

+1

Hiển thị trực quan vấn đề – antipattern

+0

Câu trả lời hay nhất tôi đã nhìn thấy cả ngày. – Baldrickk

+0

Cảm ơn rất nhiều ^^. – Oh2

-2

Để khắc phục sự cố như vậy, bạn cũng có thể đưa ra tuyên bố chuyển tiếp. Nhưng vấn đề nằm trong những gì Martin J đã nói.

class Node; 

class Node { 
public: 
    int data; 
    Node* x; 
}; 

gấu trong tâm trí này không được kiểm tra

+2

Đó là không cần thiết, tại thời điểm bạn tuyên bố một con trỏ đến' Node', trình biên dịch đã biết đó là tên của một lớp, thậm chí không cần khai báo trước – Dettorer

+0

Bạn không biết mình đã làm bài viết của mình chưa. Nếu vậy lý do là lý do tại sao? – Blaatz0r

+0

Tôi đã làm, bởi vì những gì tôi đã nói (câu trả lời của bạn, trong khi không có hại, không giúp và không thêm gì vào các câu trả lời hiện có) và một phần vì "chưa được kiểm tra": D. khi bạn không biết nếu nó hoạt động (đặc biệt là cho một ngắn như vậy và dễ dàng để kiểm tra một) – Dettorer

0

Trình biên dịch cần phải biết loại hoàn toàn của A khi nó sáng lập nó bên trong lớp A. Vì A là không đầy đủ, nó không thể xác định kích thước của nó, nó không thể xác định bao nhiêu không gian biến thành viên một sẽ mất, do đó nó sẽ không biên dịch nó.

Các vấn đề liên quan