2009-09-03 69 views
13

bất cứ ai có thể cho tôi biết những gì là sự khác biệt giữa:C++ con trỏ đến lớp

Display *disp = new Display(); 

Display *disp; 
disp = new Display(); 

Display* disp = new Display(); 

Display* disp(new Display()); 
+0

Nhưng tại sao "Display mới" trong trường hợp đầu tiên và "GzDisplay mới" trong lần thứ hai? –

+0

cũng có bất kỳ sự khác biệt nào trong "Hiển thị * disp = new Display();" –

+0

Không, câu hỏi của bạn không phải là "có mùi". Tiếp tục đặt câu hỏi của bạn và chúng tôi sẽ tiếp tục trả lời câu hỏi của bạn. :) – jdelator

Trả lời

14

Trường hợp thứ nhất:

Display *disp = new Display(); 

Liệu ba điều:

  1. Nó tạo ra một biến mới disp, với kiểu Display*, đó là một con trỏ đến một đối tượng kiểu Display, và sau đó
  2. Nó phân bổ đối tượng Display mới trên heap và
  3. Nó đặt disp var có thể trỏ đến đối tượng Display mới.

Trong trường hợp thứ hai:

Display *disp; disp = new GzDisplay(); 

Bạn tạo một biến disp với loại Display*, và sau đó tạo ra một đối tượng của một loại khác nhau, GzDisplay, trên heap, và gán con trỏ của nó để biến số disp.

Điều này sẽ chỉ hoạt động nếu GzDisplay là lớp con của Hiển thị. Trong trường hợp này, nó trông giống như một ví dụ của polymorphism.

Ngoài ra, để giải quyết nhận xét của bạn, không có chênh lệch giữa tờ khai:

Display* disp; 

Display *disp; 

Tuy nhiên, do cách C quy tắc kiểu làm việc, có sự khác biệt giữa :

Display *disp1; 
Display* disp2; 

Display *disp1, disp2; 

Bởi vì trong trường hợp đó cuối cùng disp1 là một con trỏ đến một đối tượng Display, có lẽ cấp phát trên heap, trong khi disp2 là một đối tượng thực tế, có lẽ cấp phát trên stack. Tức là, trong khi con trỏ được cho là một phần của kiểu, thì trình phân tích cú pháp sẽ liên kết nó với biến đó.

+2

Anh ấy đã thay đổi câu hỏi. GzDisplay không còn tồn tại nữa. –

+0

@Daniel: Tôi nghĩ bạn đang bối rối; SO chỉ hiển thị tác giả của bản chỉnh sửa gần đây nhất; bạn phải bấm vào "17 phút trước" (hoặc bất cứ lúc nào nó hiển thị cho bạn) để xem tất cả các sửa đổi, và những người làm cho họ. Khi bạn làm điều đó, bạn sẽ khám phá ra rằng áp phích ban đầu đã thay đổi câu hỏi. Nhận xét tại meta.stackoverflow.com nếu bạn cảm thấy giao diện người dùng khó hiểu. – derobert

+0

@derobert: Lời xin lỗi của tôi. Tôi đã xóa nhận xét của mình. –

0

Một người tạo ra một đối tượng thuộc loại Display và một trong các loại GzDisplay, có chủ đích hay là lỗi đánh máy?

Nếu đó là lỗi đánh máy thì không có sự khác biệt về mã được tạo nhưng phương thức đầu tiên được ưu tiên vì không có thời gian trong đó biến số disp nằm trong phạm vi và chưa được khởi tạo.

0

1) Ví dụ của GzDisplay được tạo trong phiên bản thứ 2, trong khi ở phiên bản thứ nhất, trường hợp được tạo là loại Hiển thị (Tôi giả sử GzDisplay là phân lớp của Hiển thị, phải không?); 2) Bên cạnh đó 1 là ngắn hơn, trong đợt 2 có giá trị không xác định cho đến khi được gán với GzDisplay mới(). Biến thể thứ hai cho bạn cơ hội vô tình quên điều đó và chèn một số mã sử dụng phân phối trước khi nó được khởi tạo.

1
Display *disp = new Display(); 

Dòng mã này tạo ra loại biến Hiển thị * và khởi tạo nó với địa chỉ của đối tượng mới được tạo.

Display *disp;  // (1) 
disp = new Display(); // (2) 

Dòng đầu tiên của mã đơn giản khai báo biến loại Hiển thị *. Tùy thuộc vào cài đặt trình biên dịch của bạn - con trỏ có thể hoặc không thể được khởi tạo. Về cơ bản, nó sẽ được coi là một con trỏ không hợp lệ, điều đó không cần thiết để trỏ tới NULL.

Dòng thứ hai gán địa chỉ của đối tượng mới được tạo cho con trỏ.

Kết quả của cả hai đoạn mã sẽ giống nhau.

Khi bật tối ưu hóa, bất kỳ trình biên dịch nào cũng sẽ tạo cùng một cụm cho cả hai. Với việc tối ưu hóa bị vô hiệu hóa và với một số mã tạo mã lỗi - cả hai đoạn mã có thể tạo mã hoàn toàn khác nhau - trong trường hợp thứ hai, con trỏ đầu tiên sẽ được khởi tạo với giá trị được trình biên dịch sử dụng cho con trỏ chưa được khởi tạo (như 0xDEADBEEF hoặc 0xEFEFEFEF - và dễ dàng nhận ra mẫu). Trong đoạn đầu tiên - con trỏ phải luôn được khởi tạo đến địa chỉ của đối tượng, bất kể cài đặt. Lưu ý, rằng đây là trình biên dịch phụ thuộc - một số trình biên dịch có thể làm như tôi nói, một số có thể làm somthing hoàn toàn khác nhau.

1

Bạn đã tìm thấy bốn cách để viết cùng một thứ.

Ví dụ 1 (Display *disp…) và 3 (Display* disp…) giống nhau; khoảng cách xung quanh * không quan trọng. Tuy nhiên, phong cách 1 thường được ưa thích, bởi vì:

Display* disp1, disp2; 

thực sự có nghĩa là:

Display *disp1, disp2; 

ví dụ: disp2 không phải là một con trỏ.

Ví dụ hai (chia tách trên hai dòng) có cùng tác dụng và có thể sẽ được biên dịch thành cùng một mã. Ví dụ thứ tư, sử dụng cú pháp khởi tạo, cũng làm như vậy.

Lưu ý rằng nếu đây là các lớp, không phải là con trỏ, có thể có sự khác biệt về hành vi và tốc độ.

+0

@Daniel: Tôi không làm như vậy. http://stackoverflow.com/revisions/1371608/list, bản sửa đổi 4, cho thấy OP thay đổi câu hỏi của riêng mình. Tôi chỉ sửa định dạng của anh ấy cho anh ấy. – derobert

+0

@derobert: Đã rút lại, lời xin lỗi của tôi. Vì tôi không có đủ đại diện để chỉnh sửa câu hỏi của người khác, tôi không biết cách tìm kiếm các bản sửa đổi trước đó của một câu hỏi. Tôi cũng đã loại bỏ nhược điểm của mình. –

5
// implicit form 
// 1) creates Display instance on the heap (allocates memory and call constructor with no arguments) 
// 2) creates disp variable on the stack initialized with pointer to Display's instance 
Display *disp = new Display(); 

// explicit form 
// 1) creates Display instance on the heap (allocates memory and call constructor with no arguments) 
// 2) creates disp variable on the stack initialized with pointer to Display's instance 
Display* disp(new Display()); 

// 1) creates uninitialized disp variable on the stack 
// 2) creates Display instance on the heap (allocates memory and call constructor with no arguments) 
// 3) assigns disp with pointer to Display's instance 
Display *disp; 
disp = new Display(); 

Sự khác biệt giữa các hình thức khởi tạo rõ ràng và ngầm định sẽ chỉ được nhìn thấy đối với các loại phức tạp với hàm tạo. Đối với loại con trỏ (Hiển thị *), không có sự khác biệt.

Để thấy sự khác biệt giữa các hình thức ngầm và rõ ràng kiểm tra mẫu sau:

#include <iostream> 

class sss 
{ 
public: 
    explicit sss(int) { std::cout << "int" << std::endl; }; 
    sss(double) { std::cout << "double" << std::endl; }; 
    // Do not write such classes. It is here only for teaching purposes. 
}; 

int main() 
{ 
sss ddd(7); // prints int 
sss xxx = 7; // prints double, because constructor with int is not accessible in implicit form 

return 0; 
} 
Các vấn đề liên quan