2009-03-06 8 views
52

Là những giống nhau:sự khác biệt giữa một con trỏ và tham số tham chiếu?

int foo(bar* p) { 
    return p->someInt(); 
} 

int foo(bar& r) { 
    return r.someInt(); 
} 

Bỏ qua các tiềm năng con trỏ null. Hai chức năng này có giống nhau về mặt chức năng cho dù someInt() là ảo hay nếu chúng được chuyển qua một số bar hoặc một lớp con của bar?

Liệu lát này bất cứ điều gì:

bar& ref = *ptr_to_bar; 

Trả lời

58

Tham chiếu C++ được cố ý không được chỉ định trong tiêu chuẩn sẽ được triển khai bằng con trỏ. Một tham chiếu giống như một "từ đồng nghĩa" với một biến hơn là một con trỏ tới nó. Ngữ nghĩa này mở ra một số tối ưu có thể cho trình biên dịch khi nó có thể nhận ra rằng một con trỏ sẽ là một overkill trong một số tình huống.

Một vài chi tiết khác biệt:

  • Bạn không thể gán NULL để tham khảo. Đây là một sự khác biệt quan trọng và lý do chính mà bạn muốn sử dụng một trên khác.
  • Khi bạn lấy địa chỉ của con trỏ , bạn sẽ nhận được địa chỉ của biến con trỏ . Khi bạn lấy địa chỉ của tham chiếu, bạn sẽ nhận được địa chỉ của biến là được đề cập.
  • Bạn không thể chỉ định lại tham chiếu. Một khi nó được khởi tạo, nó trỏ đến cùng một đối tượng cho toàn bộ cuộc sống của nó.
+5

Bạn thực sự có thể gán NULL đến một tài liệu tham khảo NẾU bạn bỏ nó vào một con trỏ của các loại và sau đó dereference điểm ví dụ int & ref = * (int *) NULL; và bạn cũng có thể gán lại một tham chiếu nếu bạn đặt nó trong một liên minh và thay đổi giá trị tương ứng trong liên minh. –

+0

Và tôi nên thêm rằng những điều này sẽ không bao giờ được thực hiện vì khi một hàm yêu cầu tham chiếu, nó không bao giờ mong đợi NULL, và mặc dù hầu hết các tham chiếu về cơ bản được thực hiện giống như con trỏ, đây không phải là trường hợp trong tất cả các kịch bản/nền tảng. –

+0

nếu bạn đang gán cho một giá trị tương ứng của một công đoàn thì bạn không thực sự gán cho một tham chiếu là bạn? – shoosh

3

tôi đã không sử dụng C++ trong một thời gian dài, vì vậy tôi thậm chí sẽ không cố gắng để thực sự trả lời câu hỏi của bạn (xin lỗi); Tuy nhiên, Eric Lippert chỉ đăng một số excellent article về con trỏ/tài liệu tham khảo mà tôi nghĩ rằng tôi sẽ chỉ cho bạn.

4

Có chức năng giống hệt nhau. Vì một tham chiếu sẽ yêu cầu bạn đặt nó vào một đối tượng trước khi sử dụng nó, bạn sẽ không phải đối phó với các con trỏ null hoặc con trỏ tới bộ nhớ không hợp lệ.

Nó cũng quan trọng để thấy sự khác biệt ngữ nghĩa:

  • Sử dụng một tài liệu tham khảo khi bạn sẽ thực sự vượt qua các đối tượng bình thường - nhưng nó là quá lớn mà nó làm cho ý nghĩa hơn để vượt qua một tham chiếu đến đối tượng chứ không phải hơn là tạo một bản sao (nếu bạn không sửa đổi đối tượng).
  • Sử dụng con trỏ khi bạn muốn xử lý địa chỉ bộ nhớ thay vì với đối tượng.
1

Các chức năng rõ ràng không phải là "giống nhau", nhưng liên quan đến hành vi ảo, chúng sẽ hoạt động tương tự. Về việc cắt, điều này chỉ xảy ra khi bạn xử lý withvalues, chứ không phải tham chiếu hoặc con trỏ.

+0

Thực ra, chúng có thể tạo ra mã máy giống hệt nhau theo nghĩa đó chúng giống nhau. – jmucchiello

13

Bỏ qua tất cả các cú pháp đường và khả năng có thể được thực hiện với một và không phải với người kia và sự khác biệt giữa con trỏ và tham khảo giải thích trong câu trả lời khác (các câu hỏi khác) ... Ừ hai có chức năng giống hệt nhau! Cả hai đều gọi hàm và cả hai đều xử lý các hàm ảo tốt như nhau.

Và không, dòng của bạn không cắt. Nó chỉ gắn kết tham chiếu trực tiếp với đối tượng được trỏ tới bởi một con trỏ.

Một số câu hỏi về lý do tại sao bạn sẽ muốn sử dụng một trong khác:

Thay vì cố gắng để đến với sự khác biệt bản thân mình, tôi ủy nhiệm bạn cho những người trong trường hợp bạn muốn biết.

3

Như mọi người khác đã đề cập, trong tham chiếu triển khai và con trỏ phần lớn là giống nhau. Có một số hãy cẩn thận nhỏ:

  • Bạn không thể gán NULL đến một tài liệu tham khảo (shoosh đề cập này): đó là đáng kể vì không có "không xác định" hoặc "không hợp lệ" tài liệu tham khảo giá trị .

  • Bạn có thể vượt qua một biến tạm thời như một const tham khảo, nhưng nó không hợp pháp để vượt qua một con trỏ để tạm thời.

Ví dụ, đây là okay:

class Thingy; // assume a constructor Thingy(int,int) 
void foo(const Thingy &a) 
{ 
    a.DoSomething(); 
} 

void bar() 
{ 
    foo(Thingy(1,2)); 
} 

nhưng hầu hết các trình biên dịch sẽ phàn nàn về

void foo2(Thingy * a); 

void bar2() 
{ 
    foo(&Thingy(1,2)); 
} 
  • Lấy địa chỉ của một biến để có được một con trỏ buộc các trình biên dịch để lưu nó vào bộ nhớ. Chỉ định tham chiếu đến biến cục bộ vừa tạo một từ đồng nghĩa; trong một số trường hợp, điều này có thể cho phép trình biên dịch giữ dữ liệu trên thanh ghi và tránh load-hit-store. Tuy nhiên, điều này chỉ áp dụng cho các biến cục bộ - khi một thứ gì đó được chuyển thành tham số bằng tham chiếu, không tránh né lưu nó vào ngăn xếp.

 

void foo() 
{ 
    int a = 5; 
    // this may be slightly more efficient 
    int &b = a; 
    printf("%d", ++b); 
    // than this 
    int *c = &a; 
    printf("%d", ++(*c)); 
} 
  • Tương tự, __restrict keyword không thể được áp dụng cho tài liệu tham khảo, chỉ có con trỏ. Bạn không thể làm số học con trỏ với các tham chiếu, vì vậy trong khi nếu bạn có một con trỏ vào một mảng thì phần tử tiếp theo trong mảng có thể có thông qua p + 1, một tham chiếu chỉ bao giờ có điểm tại một điểm trong nó. toàn bộ cuộc sống.

4

Không chắc chắn nếu có ai trả lời câu hỏi thứ 2 của bạn ẩn ở dưới cùng về việc cắt ... không có điều đó sẽ không gây ra việc cắt.

Cắt lát là khi một đối tượng dẫn xuất được gán (sao chép) cho một đối tượng lớp cơ sở - chuyên môn của lớp dẫn xuất bị "cắt".Lưu ý rằng tôi đã nói rằng đối tượng được sao chép, chúng tôi không nói về các con trỏ được sao chép/gán, mà chính các đối tượng đó.

Trong ví dụ của bạn, điều đó không xảy ra. Bạn chỉ cần de-tham chiếu một con trỏ đến một đối tượng Bar (do đó dẫn đến một đối tượng Bar) đang được sử dụng như là rvalue trong một khởi tạo tham chiếu. Không chắc chắn tôi đã nhận được thuật ngữ của mình ...

11

Tham chiếu là con trỏ không đổi tức là bạn không thể thay đổi tham chiếu để tham chiếu đến đối tượng khác. Nếu bạn thay đổi, giá trị của đối tượng tham chiếu sẽ thay đổi.

Đối với Ex:

 int j = 10; 
     int &i = j; 
     int l = 20; 
     i = l; // Now value of j = 20 

     int *k = &j; 
     k = &l; // Value of j is still 10