Khai báo hàm – khai báo hàm trong c ++

Bạn đang xem : khai báo hàm trong c ++

Từ cppreference.com

Một khai báo hàm giới thiệu tên hàm và loại của nó. Định nghĩa hàm liên kết tên / kiểu hàm với thân hàm.

chỉnh sửa ]

Khai báo hàm

Khai báo hàm có thể xuất hiện trong bất kỳ phạm vi nào. Khai báo hàm ở phạm vi lớp giới thiệu hàm thành viên lớp (trừ khi sử dụng chỉ định bạn bè), hãy xem các hàm thành viên chức năng kết bạn để biết chi tiết.

Loại hàm đang được khai báo bao gồm (được cung cấp bởi khai báo-specifier-seq của cú pháp khai báo ) và bộ khai báo hàm

noptr-decarator

(

tham số-danh sách

< mã> )

cv

(tùy chọn)

ref

(tùy chọn)

ngoại trừ

(tùy chọn)

attr

(tùy chọn)

(1)

noptr-decarator

(

tham số-danh sách

< mã> )

cv

(tùy chọn)

ref

(tùy chọn)

ngoại trừ

(tùy chọn)

attr

(tùy chọn)

- & gt ;

dấu vết

(2)

(kể từ C ++ 11)

(xem Khai báo để biết các dạng khác của cú pháp trình khai báo)

1)

Cú pháp khai báo hàm thông thường

2)

Khai báo kiểu trả về sau: kiểu trả về theo sau chỉ được phép trên bộ khai báo hàm ngoài cùng. Khai báo-specifier-seq trong trường hợp này phải chứa từ khóa auto

noptr-decarator

bất kỳ dấu khai báo

hợp lệ nào

, nhưng nếu nó bắt đầu bằng *, & amp ;, hoặc & amp; & amp ;, thì nó phải được bao quanh bởi dấu ngoặc đơn.

tham số-danh sách

có thể trống, danh sách các tham số hàm được phân tách bằng dấu phẩy (xem bên dưới để biết chi tiết)

attr

(kể từ C ++ 11)

danh sách tùy chọn gồm thuộc tính . Các thuộc tính này được áp dụng cho kiểu của hàm, không phải bản thân hàm. Các thuộc tính cho hàm xuất hiện sau mã định danh trong bộ khai báo và được kết hợp với các thuộc tính xuất hiện trong phần đầu của khai báo, nếu có.

cv

đủ điều kiện const / biến động, chỉ được phép trong khai báo hàm thành viên không tĩnh

tham khảo

(kể từ C ++ 11)

tái chứng nhận, chỉ được phép trong khai báo hàm thành viên không tĩnh

ngoại trừ

thông số kỹ thuật ngoại lệ động

(cho đến khi C ++ 11)

hoặc thông số kỹ thuật ngoại lệ động
hoặc thông số kỹ thuật không chấp nhận

(kể từ C ++ 11)

( cho đến C ++ 17)

noexcept Specification

(kể từ C ++ 17)

Lưu ý rằng đặc tả ngoại lệ không phải là một phần của loại hàm

(cho đến khi C ++ 17)

dấu vết

Kiểu trả về theo sau, hữu ích nếu kiểu trả về phụ thuộc vào tên đối số, chẳng hạn như

template

& lt;

class

T,

class

U

& gt;

auto

add

(

T t, U u

) < / p>

& gt;

tuyên bố

(

t

+

u

)

;

hoặc phức tạp, chẳng hạn như trong

auto

fpif

(

< p class = "kw4"> int

)

& gt;

int

(

*

)

(

int

)

Như đã đề cập trong Khai báo , bộ khai báo có thể được theo sau bởi một mệnh đề, mệnh đề này khai báo các ràng buộc được liên kết cho chức năng, phải được đáp ứng để chức năng được chọn theo độ phân giải quá tải . (ví dụ: void f1 (int a) yêu cầu true;) Lưu ý rằng ràng buộc liên quan là một phần của chữ ký hàm, nhưng không phải là một phần của kiểu hàm.

(kể từ C ++ 20)

Các bộ khai báo hàm có thể được trộn với các bộ khai báo khác, nơi khai báo-specifier-seq cho phép:

 

// khai báo một int, một int *, một hàm và một con trỏ đến một hàm

int

a

=

1

,

*

p

=

NULL

, f

(< / p>

)

,

(

*

pf

)

(

gấp đôi

)

;

// khai báo-specifier-seq là int

// bộ khai báo f () khai báo (nhưng không xác định)

// một hàm không nhận đối số và trả về int

struct

S

{

virtual

int

f

(

char < / p>

)

const

, g

(

int

)

& amp; & amp;

;

< p class = "co1"> // khai báo hai hàm thành viên không tĩnh

virtual

int

f

(

char < / p>

)

, x

;

// lỗi thời gian biên dịch: virtual (trong phần khai báo -specifier-seq)

// chỉ được phép trong khai báo không tĩnh

// hàm thành viên

}

;

Việc sử dụng loại đối tượng đủ điều kiện dễ bay hơi làm loại tham số hoặc loại trả về không được dùng nữa.

(kể từ C ++ 20)

Kiểu trả về của hàm không thể là kiểu hàm hoặc kiểu mảng (nhưng có thể là con trỏ hoặc tham chiếu đến những hàm đó).

Như với bất kỳ khai báo nào, các thuộc tính xuất hiện trước khai báo và các thuộc tính xuất hiện ngay sau mã định danh trong bộ khai báo đều áp dụng cho thực thể đang được khai báo hoặc định nghĩa (trong trường hợp này là cho hàm):

 

[

[

noreturn

]

]

void

f

[

[ noreturn

]

]

(

)

;

// được: cả hai thuộc tính đều áp dụng cho hàm f

Tuy nhiên, các thuộc tính xuất hiện sau dấu khai báo (trong cú pháp ở trên), áp dụng cho kiểu của hàm, không áp dụng cho chính hàm:

 

void

f

(

)

[

[

noreturn

]

]

;

// error: thuộc tính này không ảnh hưởng đến chính hàm

(kể từ C ++ 11)

Như với bất kỳ khai báo nào, loại hàm func được khai báo là ret func (params) ret (params) (ngoại trừ hàm viết lại kiểu tham số được mô tả bên dưới): xem đặt tên loại .

Khấu trừ loại trả lại

Nếu khai báo hàm chứa từ khóa auto , kiểu trả về theo sau có thể bị bỏ qua và sẽ được trình biên dịch suy ra từ kiểu biểu thức được sử dụng trong return tuyên bố. Nếu kiểu trả về không sử dụng statementtype (auto) , thì việc khấu trừ tuân theo các quy tắc của chiết khấu đối số mẫu :

 

int

x

=

1

;

auto

f

(

)

{< / p>

return

x

;

}

// kiểu trả về là int

const

auto

& amp;

f

(

)

{

trả về

x

;

}

// kiểu trả về là const int & amp;

Nếu kiểu trả về là statementtype (auto) , thì kiểu trả về giống như những gì sẽ nhận được nếu biểu thức được sử dụng trong câu lệnh trả về được bao bọc trong loại khai báo :

 

int

x

=

1

;

Khai báo

(

auto

)

f

(

)

{

trả về

x

;

}

// kiểu trả về là int, giống như kiểu khai báo (x)

Khai báo

(

auto

)

f

(

)

{

trả về

(

x

)

;

}

// kiểu trả về là int & amp ;, tương tự như kiểu khai báo ((x))

(lưu ý: “ const statementtype (auto) & amp; ” là một lỗi, dectype (auto) phải được sử dụng riêng)

Nếu có nhiều câu lệnh trả về, tất cả chúng phải suy ra cùng một loại:

 

auto

f

(

bool

val < p class = "br0">)

{

if

(

val

)

return < / p>

123

;

// suy ra kiểu trả về int

else

return

3,14f

; < / p>

// error: suy ra kiểu trả về float

}

Nếu không có câu lệnh trả về hoặc nếu đối số của câu lệnh trả về là một biểu thức void, thì kiểu trả về đã khai báo phải là kiểu khai báo (auto) , trong trường hợp đó kiểu trả về được suy ra là vô hiệu, hoặc (có thể là cv đủ điều kiện) tự động, trong trường hợp đó kiểu trả về được suy ra sau đó (về cơ bản là đủ điều kiện cv):

 

auto

f

(

)

{

}

// trả về void

auto

g

(

)

{< / p>

return

f

(

)

;

}

// trả về void

auto

*

x

(

) < / p>

{

}

// error: không thể suy ra auto * từ void

Khi một câu lệnh trả về đã được nhìn thấy trong một hàm, kiểu trả về được suy ra từ câu lệnh đó có thể được sử dụng trong phần còn lại của hàm, bao gồm cả trong các câu lệnh trả về khác:

 

auto

sum

(

int

i < p class = "br0">)

{

if

(

i

==

1

)

return

i

;

// kiểu trả về của sum là int

khác

return

sum

(

i

-

1

)

+

i

;

// okay: kiểu trả về của sum đã được biết rồi

}

Nếu câu lệnh trả về sử dụng dấu ngoặc nhọn-init-list, thì không được phép khấu trừ:

 

auto

func

(

)

{

trả về

{

1

,

2

,

3

}

;

}

// lỗi

Các hàm ảo coroutines (kể từ C ++ 20) không thể sử dụng kiểu khấu trừ trả về:

 

struct

F

{

virtual

auto

f

(

) < / p>

{

trả về

2

;

}

// lỗi

}

;

Mẫu hàm khác với các hàm chuyển đổi do người dùng xác định có thể sử dụng khấu trừ kiểu trả về. Việc khấu trừ diễn ra tại thời điểm khởi tạo ngay cả khi biểu thức trong câu lệnh trả về không phải là phụ thuộc . Bản thuyết minh này không có trong ngữ cảnh tức thì cho các mục đích của SFINAE .

 

mẫu

& lt;

class

T < p class = "sy1"> & gt;

auto

f

(

T

)

{

trả về

t

;

}

typedef

khai báo

(

f

(

1

)

)

fint_t

;

// khởi tạo f & lt; int & gt; để suy ra loại trả lại

mẫu

& lt;

class

T

& gt ;

auto

f

(

T

*

t

)

{

trả về

*

t

;

}

void

g

(

)

{< / p>

int

(

*

p

)

(

int

*

)

=

& amp;

f

;

< p class = "br0">}

// khởi tạo cả hai f để xác định kiểu trả về,

// chọn quá tải mẫu thứ hai

Các khai báo lại hoặc chuyên môn hóa của hàm hoặc mẫu hàm sử dụng loại trừ kiểu trả về phải sử dụng cùng một loại trả về chỗ dành sẵn:

 

auto

f

(

int

num < p class = "br0">)

{

return

num

;

}

// int f (int num); // error: không có loại trả về trình giữ chỗ

// khai báo (auto) f (int num); // error: other placeholder

mẫu

& lt;

typename

T

& gt ;

auto

g

(

T

)

{

trả về

t

;

}

template

auto

g

(

int < / p>

)

;

// được rồi: kiểu trả về là int

// mẫu char g (char); // error: không phải là một chuyên môn hóa của mẫu chính g

Tương tự, các khai báo lại hoặc chuyên môn hóa của các hàm hoặc các mẫu hàm không sử dụng kiểu khấu trừ trả về không được sử dụng trình giữ chỗ:

 

int

f

(

int

num < p class = "br0">)

;

// auto f (int num) {return num; } // error: không phải là một khai báo lại của f

mẫu

& lt;

typename

T

& gt ;

T g

(

T

)

{

trả về

t

;

}

mẫu

int

g

(

int < / p>

)

;

// được rồi: chuyên T là int

// mẫu auto g (char); // error: không phải là một chuyên môn hóa của mẫu chính g

Khai báo thuyết minh rõ ràng không tự khởi tạo các mẫu hàm mà sử dụng loại khấu trừ trả lại:

 

mẫu

& lt;

typename

T < p class = "sy1"> & gt;

auto

f

(

T

)

{

trả về

t

;

}

extern

mẫu

auto

f

(< / p>

int

)

;

// không khởi tạo f & lt; int & gt;

int

(

*

p

) < / p>

(

int

)

=

f

;

// khởi tạo f & lt; int & gt; để xác định loại trả lại của nó,

// nhưng một định nghĩa thuyết minh rõ ràng

// vẫn được yêu cầu ở đâu đó trong chương trình

(kể từ C ++ 14)

chỉnh sửa ]

Danh sách thông số

Danh sách tham số xác định các đối số có thể được chỉ định khi hàm được gọi. Đây là danh sách được phân tách bằng dấu phẩy, mỗi danh sách có cú pháp sau:

attr

(tùy chọn)

statement-specifier-seq

bộ khai báo

(1)

attr

(tùy chọn)

statement-specifier-seq

bộ khai báo

=

bộ khởi tạo

(2)

attr

(tùy chọn)

decifier-seq

trừu tượng-khai báo

(tùy chọn) < / p>

(3)

attr

(tùy chọn)

statement-specifier-seq

trừu tượng-khai báo

(tùy chọn)

=

trình khởi tạo

(4)

void

(5)

1)

Khai báo một tham số được đặt tên (chính thức). Để biết ý nghĩa của

statement-specifier-seq

khai báo

, hãy xem

 

int

f

(

int

a,

int

*

p,

int

(

*

(

*

x

)

(

gấp đôi

)

)

[

3

]

)

;

Khai báo một tham số được đặt tên (chính thức). Để biết ý nghĩa của và, hãy xem khai báo

2)

Khai báo một tham số được đặt tên (chính thức) với

 

int

f

(

int

a

=

7

,

int

*

p

=

nullptr,

int

(< / p>

*

(

*

x

)

(

gấp đôi

)

)

[

3

]

=

nullptr

)

;

Khai báo một tên (chính thức) tham số có giá trị mặc định

3)

Khai báo một tham số không có tên.

 

int

f

(

int

, < p class = "kw4"> int

*

,

int

(

*

(

*

)

(

gấp đôi

)

)

[

3

]

)

;

Khai báo một tham số không có tên.

4) < / p> Khai báo một tham số không tên với

 

int

f

(

int

=

7

,

int

*

=

nullptr,

int

(

*

(

*

)

(

gấp đôi

)

< p class = "br0">)

[

3

]

=

nullptr

)

;

Khai báo một tham số chưa được đặt tên với giá trị mặc định

5)

Cho biết rằng hàm không nhận tham số, nó là từ đồng nghĩa chính xác với danh sách tham số trống:

int

f

(

void

)

;

int

f

(

)

;

khai báo cùng một hàm. Lưu ý rằng không thể sử dụng kiểu void (có thể là cv-đủ điều kiện) trong danh sách tham số:

< p class = "kw4"> int

f

(

void

,

int < / p>

)

;

int

f

(

const

void

)

;

là lỗi ( mặc dù các kiểu dẫn xuất, chẳng hạn như void * có thể được sử dụng). Trong một mẫu, chỉ có thể sử dụng kiểu void không phụ thuộc (một hàm nhận một tham số duy nhất của kiểu T không trở thành một hàm không tham số nếu được khởi tạo bằng T = void ).

Một dấu chấm lửng ... có thể xuất hiện ở cuối danh sách tham số; điều này khai báo một variadic function :

 

int

printf

(

const

char

*

fmt ...

)

;

Để tương thích với C89, dấu phẩy tùy chọn có thể xuất hiện trước dấu chấm lửng nếu danh sách tham số chứa ít nhất một tham số:

 

int

printf

(

const

char

* fmt, ...

)

;

// OK, tương tự như trên

Mặc dù khai báo-specifier-seq ngụ ý rằng có thể tồn tại specifier ngoài các chỉ định kiểu, nhưng chỉ số chỉ định khác được phép là đăng ký cũng như tự động (cho đến khi C + +11), và nó không có hiệu lực.

(cho đến khi C ++ 17)

Nếu bất kỳ tham số hàm nào sử dụng (tự động hoặc loại khái niệm ), thì khai báo hàm thay vào đó là mẫu hàm viết tắt khai báo:

 

void

f1

(

auto

)

;

// giống với mẫu & lt; class T & gt; void f (T)

void

f2

(

C1

auto

)

;

// giống với mẫu & lt; C1 T & gt; void f7 (T), nếu C1 là một khái niệm

(kể từ C ++ 20)

Tên tham số được khai báo trong khai báo hàm thường chỉ dành cho mục đích tự lập tài liệu. Chúng được sử dụng (nhưng vẫn là tùy chọn) trong các định nghĩa hàm.

Loại của mỗi tham số hàm trong danh sách tham số được xác định theo các quy tắc sau:

1)

Đầu tiên,

statement-specifier-seq

và bộ khai báo được kết hợp như trong bất kỳ

Đầu tiên, và bộ khai báo được kết hợp như trong bất kỳ khai báo nào để xác định loại.

2)

Nếu kiểu là "mảng T" hoặc "mảng chưa biết giới hạn của T", nó được thay thế bằng kiểu "con trỏ tới T"

3)

Nếu kiểu là kiểu hàm F, nó được thay thế bằng kiểu "con trỏ tới F"

4)

Vòng loại cv cấp cao nhất bị loại bỏ khỏi loại tham số (Điều chỉnh này chỉ ảnh hưởng đến loại chức năng, nhưng không ảnh hưởng đến ' t sửa đổi thuộc tính của tham số:

int

f

(

const

int

p, khai báo

(

p

)

*

)

;

int

f

(

int

,

const

int

*

)

;

khai báo tương tự chức năng)

Do các quy tắc này, các khai báo hàm sau đây khai báo chính xác cùng một hàm:

 

int

f

(

char

s < p class = "br0"> [

3

]

)

;

int

f

(

char

[< / p>

]

)

;

int

f

(

char

* < / p> s

)

;

int

f

(

char

* < / p>

const

)

;

int

f

(

char

* < / p>

dễ bay hơi

s

)

;

Các khai báo sau cũng khai báo chính xác cùng một hàm:

 

int

f

(

int

(

)

)

;

int

f

(

int

(< / p>

*

g

)

(

)

)

;

Sự mơ hồ nảy sinh trong danh sách tham số khi tên kiểu được lồng trong dấu ngoặc đơn (bao gồm biểu thức lambda ) (kể từ C ++ 11). Trong trường hợp này, sự lựa chọn là giữa việc khai báo một tham số kiểu con trỏ tới hàm và khai báo một tham số có dấu ngoặc đơn thừa xung quanh mã định danh của bộ khai báo. Biện pháp giải quyết là coi tên kiểu là mã định nghĩa kiểu đơn giản (là con trỏ đến kiểu hàm):

 

class

C

{

}

;

void

f

(

int

(< / p> C

)

)

{

}

// void f (int (* fp) (C param)) {}

// KHÔNG void f (int C) {}

void

g

(

int

* < / p>

(

C

[

10

]

)

)

;

// void g (int * (* fp) (C param [10]));

// NOT void g (int * C [10]);

Kiểu tham số không được là kiểu bao gồm tham chiếu hoặc con trỏ tới mảng không xác định ràng buộc, bao gồm một con trỏ / mảng nhiều cấp của các kiểu như vậy hoặc một con trỏ đến các hàm có tham số là các kiểu như vậy.

Dấu chấm lửng cho biết variadic đối số không cần đặt trước dấu phẩy, ngay cả khi dấu chấm lửng sau dấu chấm lửng cho biết gói thông số , vì vậy các mẫu hàm sau đây hoàn toàn giống nhau:

 

mẫu

& lt;

typename

.. .

Args

& gt;

void

f

(

Args ..., ...

)

;

template

& lt;

typename

...

Args

& gt;

void

f

(

Args ... ...

)

;

template

& lt;

typename

...

Args

& gt;

void

f

(

Args ......

)

;

Một ví dụ về thời điểm khai báo như vậy có thể được sử dụng là khả năng triển khai của std :: is_ functions .

Chạy mã này

 

# include & lt; cstdio & gt;

template

& lt;

typename

...

Variadic

,

typename

...

Args

& gt;

constexpr

void

gọi

(

auto < / p>

(

*

vui

)

(

Đa dạng ......

)

, Args ...

args

)

{

vui vẻ

(

args ...

)

;

}

int

main

(

)

{

gọi

(

std ::

printf

,

"% dm •% dm •% dm =% d% s% c"

,

2

,

3

,

7

,

2

*

3

*

7

,

"m³" < / p>,

'

\ n

'

)

;

}

Kết quả:

 2m • 3m • 7m = 42m³ 

(kể từ C ++ 11)

chỉnh sửa ]

Định nghĩa hàm

Định nghĩa hàm không phải là thành viên chỉ có thể xuất hiện trong phạm vi không gian tên (không có hàm lồng nhau). Định nghĩa hàm thành viên cũng có thể xuất hiện trong phần nội dung của định nghĩa lớp . Chúng có cú pháp sau:

attr

(tùy chọn)

statement-specifier-seq

(tùy chọn)

bộ khai báo

Virt-specifier-seq

(tùy chọn)

function-body

trong đó function-body là một trong những phần sau

ctor-initializer

(tùy chọn)

câu lệnh ghép

(1)

function-try-block

(2)

= xóa ;

(3)

(kể từ C ++ 11)

= default ;

(4)

(kể từ C ++ 11)

1)

thân hàm thông thường

2)

function-try-block (là một phần thân hàm thông thường được bao bọc trong một khối try / catch)

3)

định nghĩa hàm đã bị xóa rõ ràng

attr

-

(kể từ C ++ 11)

danh sách các thuộc tính tùy chọn. Các thuộc tính này được kết hợp với các thuộc tính sau mã định danh trong bộ khai báo

(xem đầu trang này), nếu có.

statement-specifier-seq

-

kiểu trả về với các từ chỉ định, như trong ngữ pháp khai báo

bộ khai báo

-

bộ khai báo hàm, giống như trong ngữ pháp khai báo hàm ở trên (có thể được đặt trong ngoặc đơn).

như với khai báo hàm, nó có thể được theo sau bởi

demand-clause

(kể từ C ++ 20)

Virt-specifier-seq

-

(kể từ C ++ 11)

ghi đè , final hoặc kết hợp của chúng theo thứ tự bất kỳ (chỉ được phép đối với các hàm thành viên không tĩnh)

ctor-initializer

-

danh sách trình khởi tạo thành viên , chỉ được phép trong các trình tạo

câu lệnh ghép

-

chuỗi câu lệnh được đặt trong dấu ngoặc nhọn tạo thành phần nội dung của một hàm

 

int

max

(

int

a,

int

b,

int

c

)

{

int

m

=

(

a

& gt ;

b

)

?

a

:

b

;

return

(

m

& gt;

c

)

?

m

:

c

;

}

// khai báo-specifier-seq là "int"

// bộ khai báo là "max (int a, int b, int c)"

// phần thân là {...}

Phần thân của hàm là một câu lệnh ghép (chuỗi không hoặc nhiều câu lệnh được bao quanh bởi một cặp dấu ngoặc nhọn), được thực thi khi thực hiện lệnh gọi hàm.

Các loại tham số cũng như kiểu trả về của định nghĩa hàm không được không đầy đủ loại lớp trừ khi hàm được xác định là đã bị xóa (kể từ C ++ 11). Kiểm tra tính đầy đủ được thực hiện trong ngữ cảnh của hàm, cho phép các hàm thành viên trả về lớp mà chúng được xác định (hoặc lớp bao quanh nó), thậm chí nếu nó không đầy đủ ở điểm định nghĩa (nó hoàn chỉnh trong phần thân hàm).

Các tham số được khai báo trong trình khai báo của định nghĩa hàm là trong phạm vi bên trong nội dung. Nếu một tham số không được sử dụng trong thân hàm, nó không cần phải được đặt tên (chỉ cần sử dụng một bộ khai báo trừu tượng là đủ):

 

void

print

(

int

a,

int

)

// tham số thứ hai không được sử dụng

{

std ::

printf

(

"a =% d

\ n

"

, a

)

;

}

Mặc dù các thông số cv-enough trên cấp cao nhất bị loại bỏ trong khai báo hàm, chúng sửa đổi kiểu của tham số hiển thị trong nội dung của một hàm:

 

void

f

(

const

int

n

)

// khai báo hàm kiểu void (int)

{

// nhưng trong phần nội dung, kiểu của n là const int

}

Các chức năng đã xóa

Nếu, thay vì một nội dung hàm, cú pháp đặc biệt = delete; được sử dụng, thì hàm được định nghĩa là. Bất kỳ việc sử dụng chức năng đã xóa nào là không hợp lệ (chương trình sẽ không biên dịch). Điều này bao gồm các cuộc gọi, cả rõ ràng (với một toán tử gọi hàm) và ngầm định (một lệnh gọi đến toán tử quá tải đã xóa, hàm thành viên đặc biệt, hàm cấp phát, v.v.), xây dựng một con trỏ hoặc con trỏ đến thành viên đến một hàm đã xóa và thậm chí cả việc sử dụng của một hàm đã xóa trong một biểu thức không được đánh giá. Tuy nhiên, ngầm định sử dụng ODR của một chức năng thành viên ảo không thuần túy sẽ bị xóa được cho phép.

Nếu chức năng bị quá tải, giải quyết quá tải sẽ diễn ra trước tiên và chương trình chỉ bị lỗi nếu chức năng đã xóa được chọn :

struct

sometype

{

void

*

toán tử mới

(

std ::

size_t

)

=

xóa

;

void

*

toán tử mới

[

]

(

std ::

size_t

)

=

xóa

;

}

;

sometype

*

p

=

new sometype

;

// error: cố gắng gọi một số kiểu đã xóa :: operator new

Định nghĩa đã xóa của một hàm phải là khai báo đầu tiên trong đơn vị dịch: một hàm được khai báo trước đó không thể được khai báo lại như đã xóa:

 

struct

sometype

{

sometype

(

< p class = "br0">)

;

}

; sometype

::

sometype

(

)

=

delete

;

// error: phải xóa trong lần khai báo đầu tiên

Chức năng do người dùng cung cấp

Một hàm là nếu nó được khai báo bởi người dùng và không được mặc định rõ ràng hoặc bị xóa trong lần khai báo đầu tiên của nó. Một hàm mặc định rõ ràng do người dùng cung cấp (tức là được mặc định rõ ràng sau lần khai báo đầu tiên) được xác định tại điểm mà nó được mặc định rõ ràng; nếu một chức năng như vậy được định nghĩa một cách ngầm định là đã bị xóa, thì chương trình đó không được hình thành. Khai báo một hàm như được mặc định sau lần khai báo đầu tiên của nó có thể cung cấp khả năng thực thi hiệu quả và định nghĩa ngắn gọn đồng thời cho phép giao diện nhị phân ổn định cho cơ sở mã đang phát triển.

 

// Tất cả các hàm thành viên đặc biệt của `trivial` là

// được đặt mặc định tương ứng trên các khai báo đầu tiên của họ,

// chúng không do người dùng cung cấp

struct

tầm thường

{

tầm thường

(

)

=

default < / p>

;

trivial

(

const

trivial

& amp;

)

=

default

;

trivial

(

trivial

& amp; & amp;

)

=

default

;

toán tử

& amp;

=

(

const

trivial

& amp;

)

=

mặc định

;

toán tử trivial

& amp;

=

(

trivial

& amp; & amp;

)

=

default

;

~ trivial

(

)

=

default

;

}

;

struct

nontrivial

{

nontrivial

(

)

;

// tuyên bố đầu tiên

}

;

// không được đặt mặc định trong khai báo đầu tiên,

// nó do người dùng cung cấp và được định nghĩa ở đây

nontrivial

::

nontrivial

(

)

=

default

;

__ func__

Trong phần thân hàm, biến xác định trước hàm-cục bộ __func__ được xác định như thể bởi

 

static

const

char

__func __

[

]

=

"function-name"

;

Biến này có phạm vi khối và thời lượng lưu trữ tĩnh:

 

struct

S

{

S

(

)

:

s

(

__func __

)

{

}

// okay: initializer-list là một phần của phần thân hàm

const

char

*

s

; < / p>

}

;

void

f

(

const

char < / p>

*

s

=

__func __

)

;

// error: tham số-danh sách là một phần của bộ khai báo

Chạy mã này

 

# include & lt; iostream & gt;

void

Foo

(

)

{< / p>

std ::

cout

& lt; & lt;

__func__

& lt; & lt;

''

;

}

Thanh

struct

{

Thanh

(

)

{

std ::

cout

& lt; & lt;

__func__

& lt; & lt;

''

;

}

~ Thanh

(

)

{

std ::

cout

& lt; & lt;

__func__

& lt; & lt;

''

;

}

struct

Quán rượu

{

Quán rượu

(

)

{

std ::

cout

& lt; & lt;

__func__

& lt; & lt;

''

< p class = "sy4">;

}

}

;

}

;

int

main

(

)

{

Foo

(

)

;

Thanh bar

;

Quán bar

::

Quán rượu

quán rượu

;

}

Đầu ra có thể có:

 Foo Bar Pub ~ Bar 

(kể từ C ++ 11)

chỉnh sửa ]

Ghi chú

Trong trường hợp không rõ ràng giữa khai báo biến sử dụng cú pháp khởi tạo trực tiếp và khai báo hàm, trình biên dịch luôn chọn khai báo hàm; xem direct-initialization .

chỉnh sửa ]

Ví dụ

chỉnh sửa ]

Báo cáo lỗi

Các báo cáo lỗi thay đổi hành vi sau đây đã được áp dụng trở về trước cho các tiêu chuẩn C ++ đã xuất bản trước đây.

DR

Áp dụng cho

Hành vi như đã xuất bản

Hành vi đúng

CWG 135

C ++ 98

các hàm thành viên được xác định trong lớp
không thể có tham số hoặc trả về
lớp riêng của nó vì nó chưa hoàn chỉnh

cho phép

CWG 393

C ++ 98

các loại bao gồm con trỏ / tham chiếu đến
mảng có giới hạn không xác định không được là tham số

những loại như vậy được phép

CWG 452

C ++ 98

danh sách khởi tạo thành viên không phải là một phần của cơ thể hàm

đã biến nó thành một phần của thân hàm bằng cách
sửa đổi cú pháp của định nghĩa hàm

CWG 577

C ++ 98

1. Loại phụ thuộc

void

để khai báo một hàm không sử dụng tham số
2. tham số có thể có cv-đủ điều kiện

void

loại hình

1. chỉ không phụ thuộc

void

là được phép
2. cv-đủ điều kiện

void


Cũng bị cấm

CWG 1327

C ++ 11

không thể
ghi đè các chức năng mặc định hoặc đã xóa bằng

ghi đè

hoặc

cuối cùng

cho phép

CWG 1355

C ++ 11

chỉ những chức năng thành viên đặc biệt mới có thể do người dùng cung cấp

mở rộng cho tất cả các chức năng

CWG 1394

C ++ 11

các hàm đã xóa không được có bất kỳ tham số nào thuộc
một loại không hoàn chỉnh hoặc trả về một loại không hoàn chỉnh

loại không đầy đủ được phép

CWG 1877

C ++ 14

kiểu khấu trừ trả về được xử lý

return

;

as

return

void

(

)

;

chỉ cần suy ra kiểu
trả về là

void

trong trường hợp này

CWG 2015

C ++ 11

việc sử dụng ngầm định một hàm ảo
đã xóa là không hợp lệ

việc sử dụng odr như vậy được miễn
khỏi việc cấm sử dụng

CWG 2044

C ++ 14

trả về kiểu khấu trừ trên các hàm trả về

void

< br /> sẽ không thành công nếu kiểu trả về được khai báo là

statementtype

(

auto

)

đã cập nhật quy tắc
khấu trừ để xử lý trường hợp này

CWG 2081

C ++ 14

khai báo lại hàm có thể sử dụng loại trả về
khấu trừ ngay cả khi khai báo ban đầu không

không cho phép

CWG 2145

C ++ 98

bộ khai báo

trong định nghĩa hàm không thể được đặt trong ngoặc đơn

cho phép

CWG 2259

C ++ 11

quy tắc giải quyết sự không rõ ràng liên quan đến tên loại
trong ngoặc đơn không bao gồm các biểu thức lambda

đề cập

chỉnh sửa ]

Xem thêm

Tài liệu C

Khai báo hàm

cho


Xem thêm những thông tin liên quan đến chủ đề khai báo hàm trong c ++

Tự học C/C++ - Bài 14 - Tìm hiểu về hàm và cách khai báo hàm trong lập trình C/C++

  • Tác giả: cafedev
  • Ngày đăng: 2020-08-06
  • Đánh giá: 4 ⭐ ( 9086 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Bài này chúng ta sẽ tìm hiểu về hàm và cách khai báo hàm trong lập trình C/C++, khi nào sử dụng nó một cách hợp lý... + Ví dụ

    Bài viết liên quan:
    1. Giới thiệu về hàm (functions) - https://cafedev.vn/tu-hoc-c-gioi-thieu-ve-ham-functions/
    2. Tìm hiểu hàm trả về giá trị - https://cafedev.vn/tu-hoc-c-tim-hieu-ham-tra-ve-gia-tri/
    3. Tìm hiểu về tham số và đối số trong hàm - https://cafedev.vn/tu-hoc-c-tim-hieu-ve-tham-so-va-doi-so-trong-ham/
    4. Giới thiệu về phạm vi(scope) của biến hoặc hàm cục bộ - https://cafedev.vn/tu-hoc-c-gioi-thieu-ve-pham-viscope-cua-bien-hoac-ham-cuc-bo/

    5. Thứ tự khai báo và định nghĩa trong C++ - https://cafedev.vn/tu-hoc-c-thu-tu-khai-bao-va-dinh-nghia-trong-c/
    5. Tìm hiểu về file Header trong C++ - https://cafedev.vn/tu-hoc-c-tim-hieu-ve-file-header-trong-c/

    Full series tự học C/C++: https://cafedev.vn/series-tu-hoc-c-c/

    Hãy cùng like, share video, đăng ký theo dõi kênh để ủng hộ cafedev làm nhiều video ý và hay hơn nhé.
    Chân thành cảm ơn ace. Chào thân ái vài quyết thắng!

    cafedevn cafedev

    Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
    @author cafedevn
    Contact: cafedevn@gmail.com
    Fanpage: https://www.facebook.com/cafedevn
    Group: https://www.facebook.com/groups/cafedev.vn/
    Instagram: https://instagram.com/cafedevn
    Twitter: https://twitter.com/CafedeVn
    Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
    Pinterest: https://www.pinterest.com/cafedevvn/
    YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/

Khai báo và gọi hàm trong C

  • Tác giả: laptrinhcanban.com
  • Đánh giá: 4 ⭐ ( 6970 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Hướng dẫn cách khai báo và gọi hàm trong C. Bạn sẽ học được cách khai báo hàm trong C, cũng như cách gọi hàm trong C đã được khai báo sau bài học này.

Hàm trong C

  • Tác giả: hoclaptrinh.vn
  • Đánh giá: 5 ⭐ ( 2460 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Mỗi chương trình C có ít nhất một hàm là hàm main(), và tất cả hầu hết các chương trình bình thường đều định nghĩa thêm các hàm.

Hàm scanf() trong C

  • Tác giả: quantrimang.com
  • Đánh giá: 4 ⭐ ( 8806 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Hàm int scanf(const char *format, ...) trong Thư viện C chuẩn đọc input đã được định dạng từ stdin.

Hàm trong C/C++

  • Tác giả: vietjack.com
  • Đánh giá: 4 ⭐ ( 1141 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Hàm trong C/C++ - Học C/C++ cơ bản và nâng cao cho người mới học từ Ngôn ngữ C/C++ hướng đối tượng, Cú pháp cơ bản, Biến, Hàm, Kiểu dữ liệu, Tính kế thừa, Nạp chồng, Tính đa hình, Tính bao đóng, Xử lý ngoại lệ, Template, Overriding, Toán tử, Vòng lặp, Điều khiển luồng, Interface, Thư viện STL, Iterator, Con trỏ, Mảng, Exception Handling, Overloading, Namespace, Thư viện chuẩn C/C++ và Signal Handling

Cách khai báo hàm trong C chi tiết

  • Tác giả: ironhackvietnam.edu.vn
  • Đánh giá: 4 ⭐ ( 2987 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Bạn chưa rõ các hàm (function) trong C và cách khai báo hàm con như thế nào? Các ví dụ, bài tập về hàm trong C của Ironhack sẽ giúp bạn!

Xem thêm các bài viết khác thuộc chuyên mục: Kiến thức lập trình

Xem Thêm  CAST và CHUYỂN ĐỔI (Transact-SQL) - SQL Server - sql ép kiểu varchar