Tham chiếu trong C++ – codecungnhau.com

Tham chiếu trong C++

Khi một biến được khai báo là một tham chiếu, nó sẽ trở thành một tên thay thế cho một biến hiện có. Một biến có thể được khai báo như một tham chiếu bằng cách đặt ‘&’ vào khai báo.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include<iostream>

using

namespace

std

;

int

main

(

)

{

  

int

x

=

10

;

  

// ref là một tham chiếu đến x.

  

int

&

ref

=

x

;

  

// Giá trị của x giờ là 20

  

ref

=

20

;

  

cout

<<

“x = “

<<

x

<<

endl

;

  

// Giá trị của x giờ đổi thành 30

  

x

=

30

;

  

cout

<<

“ref = “

<<

ref

<<

endl

;

  

return

0

;

}

Kết quả:
x = 20
ref = 30

Ứng dụng

1. Sửa đổi các tham số đã truyền trong một hàm

Nếu một hàm nhận được một tham chiếu đến một biến, nó có thể sửa đổi giá trị của biến đó. Ví dụ, các biến chương trình sau đây được hoán đổi bằng cách sử dụng các tham chiếu.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include<iostream>

using

namespace

std

;

void

swap

(

int

&

first

,

int

&

second

)

{

    

int

temp

=

first

;

    

first

=

second

;

    

second

=

temp

;

}

int

main

(

)

{

    

int

a

=

2

,

b

=

3

;

    

swap

(

a

,

b

)

;

    

cout

<<

a

<<

” “

<<

b

;

    

return

0

;

}

Kết quả: 3 2

Chúng ta cũng có thể sử dụng các tham chiếu trong vòng lặp for each để sửa đổi tất cả các phần tử.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <bits/stdc++.h>

using

namespace

std

;

int

main

(

)

{

    

vector

<

int

>

vect

{

10

,

20

,

30

,

40

}

;

    

// Ta có thể chính sửa các

    

// phần tử sử dụng tham chiếu.

    

for

(

int

&x

:

vect

)

        

x

=

x

+

5

;

    

// Hiển thị các phần tử.

    

for

(

int

x

:

vect

)

      

cout

<<

x

<<

” “

;

    

return

0

;

}

2. Tránh sao chép các cấu trúc lớn

Hãy tưởng tượng một hàm phải nhận một đối tượng lớn. Nếu chúng ta chuyển nó mà không có tham chiếu, một bản sao mới của nó sẽ được tạo ra, gây lãng phí thời gian và bộ nhớ của CPU. Chúng ta có thể sử dụng tham chiếu để tránh điều này.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

struct

Student

{

  

string

name

;

  

string

address

;

  

int

rollNo

;

}

// Nếu ta bỏ &, một bản sao của

// đối tượng student sẽ được tạo

// Ta sử dụng const để tránh các thay đổi

// không mong muốn trên đối tượng vì hàm

// chỉ dùng để hiện thị đối tượng.

void

print

(

const

Student

&s

)

{

    

cout

<<

s

.

name

<<

”  “

<<

s

.

address

<<

”  “

<<

s

.

rollNo

;

}

Tương tự, đối với vòng lặp for each.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <bits/stdc++.h>

using

namespace

std

;

int

main

(

)

{

    

vector

<

string

>

vect

{

“geeksforgeeks practice”

,

                    

“geeksforgeeks write”

,

                    

“geeksforgeeks ide”

}

;

    

// Tránh sao Chép toàn bộ đối

    

// tượng chuỗi bằng tham chiếu.

    

for

(

const

auto

&x

:

vect

)

      

cout

<<

x

<<

endl

;

    

return

0

;

}

Tham chiếu và con trỏ

Cả hai tham chiếu và con trỏ đều có thể được sử dụng để thay đổi các biến cục bộ của một hàm bên trong một hàm khác. Cả hai cũng có thể được sử dụng để lưu việc sao chép các đối tượng lớn khi được truyền làm đối số cho các hàm hoặc trả về từ các hàm, để đạt được hiệu quả. Mặc dù có những điểm tương đồng ở trên, nhưng có những điểm khác biệt sau đây giữa tham chiếu và con trỏ.

  1. Một con trỏ có thể được khai báo là void nhưng một tham chiếu thì không bao giờ.
  2. Biến con trỏ có n cấp / nhiều cấp chuyển hướng, tức là con trỏ đơn, con trỏ kép, con trỏ ba. Trong khi đó, biến tham chiếu chỉ có một / một mức chuyển hướng duy nhất.

Xem thêm về sự khác biệt giữa con trỏ và tham chiếu ở đây.

Tham chiếu không mạnh như con trỏ

  • Sau khi một tham chiếu được tạo, nó không thể được thực hiện để tham chiếu đến một đối tượng khác; nó không thể được gán lại. Điều này thường thực hiện được với con trỏ.
  • Tham chiếu không được NULL. Con trỏ thường được tạo NULL để chỉ ra rằng chúng không trỏ đến bất kỳ thứ hợp lệ nào.
  • Một tham chiếu phải được khởi tạo khi khai báo. Không có hạn chế như vậy với con trỏ.

Do các hạn chế ở trên, tham chiếu trong C++ không thể được sử dụng để triển khai cấu trúc dữ liệu như Danh sách liên kết, Cây, … Trong Java, tham chiếu không có các hạn chế nêu trên và có thể được sử dụng để triển khai tất cả các cấu trúc dữ liệu. Tham chiếu mạnh hơn trong Java là lý do chính khiến Java không cần con trỏ.

Tham chiếu an toàn và dể dùng hơn con trỏ

  • An toàn hơn: Vì các tham chiếu phải được khởi tạo, các tham chiếu “hoang dã” như con trỏ “hoang dã” không có khả năng tồn tại. Tuy nhiên, vẫn có thể có các tham chiếu không tham chiếu đến một vị trí hợp lệ (Xem câu hỏi 5 và 6 trong bài tập bên dưới)
  • Dễ sử dụng hơn: Tham chiếu không cần toán tử dereference (*) để truy cập giá trị. Chúng có thể được sử dụng giống như các biến bình thường. Toán tử (&) chỉ cần thiết tại thời điểm khai báo. Ngoài ra, các thành viên của một tham chiếu đối tượng có thể được truy cập bằng toán tử (.), Không giống như các con trỏ cần toán tử (->) để truy cập các thành viên.

Cùng với những lý do trên, có rất ít nơi như đối số của hàm tạo bản sao (copy constructor) không thể sử dụng con trỏ. Tham chiếu phải được sử dụng để chuyển đối số trong phương thức khởi tạo bản sao. Tương tự, các tham chiếu phải được sử dụng để nạp chồng một số toán tử như ++.

Bài tập tìm hiểu thêm

Dự đoán kết quả của các chương trình sau. Nếu có lỗi biên dịch, hãy sửa chúng.

Câu hỏi 1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

#include<iostream>

using

namespace

std

;

int

&

fun

(

)

{

    

static

int

x

=

10

;

    

return

x

;

}

int

main

(

)

{

    

fun

(

)

=

30

;

    

cout

<<

fun

(

)

;

    

return

0

;

}

Câu hỏi 2

1

2

3

4

5

6

7

8

9

10

11

12

#include<iostream>

using

namespace

std

;

int

fun

(

int

&x

)

{

    

return

x

;

}

int

main

(

)

{

    

cout

<<

fun

(

10

)

;

    

return

0

;

}

Câu hỏi 3

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include<iostream>

using

namespace

std

;

void

swap

(

char

*

&str1

,

char

*

&str2

)

{

  

char

*

temp

=

str1

;

  

str1

=

str2

;

  

str2

=

temp

;

}

int

main

(

)

{

  

char

*

str1

=

“CODE”

;

  

char

*

str2

=

“CUNG NHAU”

;

  

swap

(

str1

,

str2

)

;

  

cout

<<

“str1 is “

<<

str1

<<

endl

;

  

cout

<<

“str2 is “

<<

str2

<<

endl

;

  

return

0

;

}

Câu hỏi 4

1

2

3

4

5

6

7

8

9

#include<iostream>

using

namespace

std

;

int

main

(

)

{

  

int

x

=

10

;

  

int

*

ptr

=

&x

;

  

int

&

*

ptr1

=

ptr

;

}

Câu hỏi 5

1

2

3

4

5

6

7

8

9

#include<iostream>

using

namespace

std

;

int

main

(

)

{

  

int

*

ptr

=

NULL

;

  

int

&ref

=

*

ptr

;

  

cout

<<

ref

;

}

Câu hỏi 6

1

2

3

4

5

6

7

8

9

10

11

12

13

14

#include<iostream>

using

namespace

std

;

int

&

fun

(

)

{

    

int

x

=

10

;

    

return

x

;

}

int

main

(

)

{

    

fun

(

)

=

30

;

    

cout

<<

fun

(

)

;

    

return

0

;

}

Chia sẻ:

  • More

Like this:

Like

Loading…