Tất cả các toán tử C ++ có trả về một cái gì đó không?


83

Tất cả các toán tử C ++ mà tôi đã làm việc trả về một cái gì đó, ví dụ: +toán tử trả về kết quả của phép cộng.

Tất cả các toán tử C ++ có trả về một cái gì đó không, hoặc có một số toán tử C ++ không trả về bất cứ điều gì?


7
Điều đó phụ thuộc vào mức độ bạn định nghĩa thuật ngữ "toán tử".
molbdnilo

12
Điều này không bị bắt buộc bởi tiêu chuẩn - ví dụ: bạn có thể triển khai +=để trả lại void, nhưng điều này không được khuyến khích. Ngoài ra, các nhà khai thác cuộc gọi hàm có thể trả lại voidvà điều này là hợp lệ
Mircea Ispas

Hừ! Tôi có linh cảm rằng toán tử phân giải phạm vi ::không trả lại bất kỳ điều gì, nhưng tôi phải tham khảo tiêu chuẩn để đảm bảo.
Yksisarvinen

2
Ngữ cảnh của câu hỏi chỉ dành cho các kiểu được cung cấp trong C ++ hay nó cũng bao gồm các kiểu do người dùng xác định?
Eljay

@Eljay Chỉ các loại được cung cấp C ++.
user8240761

Câu trả lời:


111

Không, không phải tất cả các toán tử đều trả về một cái gì đó.

Mặc dù chúng có thể không chính xác như những gì bạn đang nghĩ, lưu ý rằng 'từ khóa' deletedelete[]C ++ thực sự là các toán tử ; và chúng được định nghĩa là có voidkiểu trả về - có nghĩa là chúng không đánh giá gì ( không phải là 'cái gì đó').

Từ cppreference :

void operator delete  ( void* ptr ) noexcept;
void operator delete[]( void* ptr ) noexcept;

13
Tôi thích câu trả lời của bạn, nó khiến tôi nghĩ về câu hỏi theo cách khác. delete, delete[], throw, (void)x;Diễn viên, bên trái của ,nhà điều hành, ngay bên của ,nhà điều hành mà sản lượng một void, một ?:ternary có sử dụng một throwcho một trong những cánh tay, dfri của operator void()(mà sẽ được người dùng định nghĩa),眠りネロク's void operator()()(mà sẽ được người dùng định nghĩa).
Eljay

10
Nó cũng gây nhầm lẫn rằng deletenhà điều hành phá hủy đối tượng và sau đó gọi operator delete. Ergo, deletetoán tử và operator deletelà những thứ riêng biệt :( stackoverflow.com/a/8918942/845092
Mooing Duck

7
Không chắc tại sao bạn lại trích dẫn các chức năng xóa khi nói về toán tử xóa. Nhưng sao cũng được.
Deduplicator

4
@MooingDuck Biểu thức xóa sẽ hủy đối tượng, rồi gọi operator delete.
NathanOliver

Xóa có tính là một toán tử thông qua không, tôi đã nghĩ rằng một đối tượng là một cái gì đó hoạt động trên một đối tượng được truyền ?? Xóa không cần bất kỳ đối tượng nào được truyền hoặc tạo để nó hoạt động ..... Cũng giống như printf .....
Yunfei Chen

82

Các nhà khai thác của các loại tùy chỉnh có thể bị quá tải để làm những điều kỳ lạ nhất.

ví dụ, toán tử + trả về kết quả của phép cộng.

Không cần thiết:

#include <iostream>
struct foo {
    int value = 0;
    void operator+(int x) {
        value += x;
    }
};

int main () {
    foo f;
    f + 3;
}

Đây operator+ thêm phía bên trái cho valuethành viên và kiểu trả về của nó là vô hiệu. Đây là một ví dụ được tạo sẵn, nhưng nói chung, việc không trả lại thứ gì đó từ một toán tử tùy chỉnh không phải là bất thường.

Toán tử duy nhất có thể bị quá tải và có yêu cầu trả lại một cái gì đó, mà tôi biết, là operator->. Nó phải trả về một con trỏ thô hoặc một đối tượng có operator->.


Thật thú vị, thực ra không có ràng buộc nào đối với giá trị trả về của toán tử quá tải. Vì vậy, các nhà khai thác có thể trả về bất cứ điều gì bạn muốn. vi.cppreference.com/w/cpp/language/operators
Bracco23

5
@ Braccor23 operator->hơi đặc biệt và cần trả về một con trỏ hoặc một đối tượng có một operator->, không chắc liệu có ngoại lệ nào khác không
idclev 463035818

1
Vâng, đó là hạn chế duy nhất. Thậm chí không bool cho các toán tử so sánh. Điều đó trông thực sự kỳ lạ.
Bracco23

9
@ idclev463035818: Một ví dụ có lẽ hữu ích hơn có thể là Mẫu biểu thức. Ví dụ: bạn có thể tạo một thư viện ma trận trong đó operator*(Matrix const& left, Matrix const& right)trả về không Matrixmà thay vào đó MatrixMul, để nếu sau đó nó được đưa vào operator+(Matrix const& left, MatrixMul const& right)hoạt động có thể là một phép nhân-cộng hợp nhất hiệu quả hơn phép nhân đầu tiên sau đó thêm
Matthieu M.

1
@DarrelHoffman Khi <<>>quá tải cho các hoạt động I / O, họ dự kiến ​​sẽ trả lại luồng để bạn có thể xếp tầng chúng:stream << foo << bar;
Barmar

34

Đối với nitpick, các nhà khai thác không trả lại bất kỳ thứ gì. Chúng chỉ là các yếu tố từ vựng mà chúng ta sử dụng để tạo ra các biểu thức trong ngôn ngữ. Bây giờ, các biểu thức có các loại và có thể đánh giá thành các giá trị, và tôi cho rằng đây là ý của bạn đối với các toán tử "trả về các thứ".

Và, vâng, vâng. Có các biểu thức C ++ với kiểu void(và do đó không đánh giá thành bất kỳ giá trị nào). Một số là hiển nhiên, những người khác ít như vậy. Một ví dụ hay sẽ là

throw std::runtime_error()

throwlà một biểu thức theo ngữ pháp C ++. Bạn có thể sử dụng nó trong các biểu thức khác, chẳng hạn như trong biểu thức điều kiện

return goodStatus() ? getValue() : throw std::runtime_error();

Và loại biểu thức ném, là void. Rõ ràng là vì điều này chỉ khiến việc thực thi nhanh chóng chuyển sang chỗ khác, nên biểu thức không có giá trị.


21

Không có toán tử C ++ nào trả về điều gì đó. Các toán tử C ++ bị quá tải trả về một cái gì đó trong chừng mực mà ký hiệu toán tử là một đường cú pháp cho một lệnh gọi hàm.

Thay vào đó, tất cả các nhà khai thác đều đánh giá một cái gì đó. Cái gì đó có giá trị cũng như kiểu được xác định rõ ràng . Ngay cả người điều hành cuộc gọi chức năng void operator()(/*params*/)cũng là một voidkiểu.

Ví dụ: +'a'là một intloại có giá trị 'a'được mã hóa trên nền tảng của bạn.

Nếu câu hỏi của bạn là "Các toán tử C ++ có thể có voidkiểu trả về không?" thì câu trả lời chắc chắn nhất là có.


14
@ idclev463035818: Đó là hạn trở lại tôi có một vấn đề với. Điều duy nhất trong C ++ trả về một cái gì đó là một hàm. Biểu thức đánh giá một cái gì đó.
Bathsheba

7
khai thác các loại hình lớp học là phương pháp mà trả lại một cái gì đó
idclev 463035818

4
Đây là một điểm quan trọng. Thuật ngữ cẩu thả dẫn đến nhầm lẫn. +1.
Pete Becker

3
@supercat - nhận xét của bạn không phù hợp với những người chăm chỉ, bao gồm cả tôi. Những người trong chúng ta đã viết tiêu chuẩn không bao giờ mong đợi người viết trình biên dịch điền thông tin chi tiết bằng cách thăm dò các trình biên dịch khác, hiện tại hay quá khứ. Mục tiêu của tiêu chuẩn là xác định rõ ràng cú pháp và ngữ nghĩa của ngôn ngữ lập trình C ++. Vâng, kết quả không hoàn hảo; có nhiều vấn đề được giải quyết trong tiêu chuẩn mới nhất chưa được giải quyết trong các phiên bản trước đó. Điều đó đến từ kinh nghiệm, nhận ra những biến chứng mà đơn giản là chưa từng thấy vào thời điểm đó.
Pete Becker

3
@ Peter-ReinstateMonica - đây là phiên bản mạnh hơn. Biểu thức I++không trả về giá trị. Nếu kiểu của ilà kiểu do người dùng định nghĩa, thì biểu thức đó được triển khai dưới dạng operator++, là một hàm trả về giá trị. Bạn gọi đó là “đường cú pháp”; Tôi gọi đó là một sự khác biệt có hậu quả quan trọng.
Pete Becker

12

Bạn thực sự có thể xác định một toán tử gọi hàm để trả về không có gì. Ví dụ:

struct Task {
   void operator()() const;
};

17
Bạn có thể xác định hầu hết mọi toán tử để không trả về gì (và đối mặt với cơn thịnh nộ của đám đông giận dữ sẽ phải duy trì mã đó)
Yksisarvinen

7
@Yksisarvinen nhưng ít nhất cái này có thể hữu ích.
Mark Ransom

11

toán tử void (): hàm chuyển đổi do người dùng xác định thành void

Bạn có thể xác định đặc biệt operator void()chức năng chuyển đổi, nơi trình biên dịch sẽ thậm chí cảnh báo bạn rằng Tđến voidchức năng chuyển đổi sẽ không bao giờ được sử dụng :

#include <iostream>

struct Foo {
    operator void() { std::cout << "Foo::operator void()!"; }
    // warning: conversion function converting 'Foo' to 
    //          'void' will never be used
};
    
int main() {
    Foo f;
    (void)f;            // nothing
    f.operator void();  // Foo::operator void()!
}

được điều chỉnh bởi [class.conv.fct] / 1

[...] Một chức năng chuyển đổi là không bao giờ sử dụng để chuyển đổi một (có thể cv-đủ điều kiện) đối tượng với cùng loại đối tượng (có thể cv-đủ điều kiện) (hoặc một tham chiếu đến nó), đến một lớp cơ sở (có thể cv-đủ điều kiện) kiểu đó (hoặc một tham chiếu đến nó), hoặc để (có thể cv-đủ điều kiện) void. 117

( 117 ) Các chuyển đổi này được coi là chuyển đổi tiêu chuẩn cho mục đích giải quyết quá tải ([over.best.ics], [over.ics.ref]) và do đó khởi tạo ([dcl.init]) và các phôi rõ ràng. Một chuyển đổi thành voidkhông gọi bất kỳ hàm chuyển đổi nào ([expr.static.cast]). Mặc dù chưa bao giờ được gọi trực tiếp để thực hiện chuyển đổi, nhưng các hàm chuyển đổi như vậy có thể được khai báo và có thể đạt được thông qua lệnh gọi hàm chuyển đổi ảo trong lớp cơ sở.

Tuy nhiên, trong khi được hiển thị ở trên, bạn vẫn có thể gọi nó bằng .operator void()cú pháp rõ ràng .


4

Các toán tử được ngôn ngữ xác định (nội trang) là các mã thông báo được sử dụng để thực hiện các loại tính toán khác nhau:

  • số học (+, -, *, /)
  • tăng / giảm (++, -)
  • phép gán (=, + =, - =, * =, / =,% =, >> =, << =, & =, ^ =, | =)
  • logic (!, &&, ||)
  • quan hệ (==,! =,>, <,> =, <=)
  • có điều kiện?
  • dấu phẩy

và như thế. Danh sách có thể rất rộng.

Trong tài liệu tham khảo ngôn ngữ như này hoặc cái này , đây là những không nhất thiết phải tham chiếu như trở về một cái gì đó, chỉ cần thực hiện một số học hoặc logic hoạt động , một sự so sánh bởi điều đó có nghĩa là một biến thể được sửa đổi, vv

Vì hoạt động này dẫn đến một số giá trị, nó có thể được hiểu là được "trả về" bởi toán tử, nhưng nó khác với giá trị trả về của hàm.

Mặt khác, các toán tử được nạp chồng có thể được định nghĩa với một giá trị trả về thuộc một số kiểu, thậm chí có thể bị vô hiệu hóa, vì vậy, không, không phải tất cả các toán tử đều trả về một số giá trị trong C ++.


3

Tôi giả sử bạn đang nói về các hàm toán tử chứ không phải toán tử như một đơn vị cú pháp của ngôn ngữ.

Nếu bạn quá tải các toán tử trên bất kỳ loại nào, bạn thực sự có thể trả về bất kỳ thứ gì bạn muốn.

Điều này cũng có ý nghĩa, bởi vì các phép toán như * hoặc () đôi khi có thể không trả về kiểu đầu vào của chúng một cách trực quan. Hãy tưởng tượng nhân một kiểu số phức với một kiểu số thực. Hoặc một toán tử trả về một phần tử từ một tập hợp.

Bạn cũng có thể nạp chồng các toán tử ++ và - để không trả về bất kỳ thứ gì, do đó loại bỏ sự trộn lẫn hiệu ứng phụ và giá trị biểu thức cực kỳ dễ xảy ra lỗi mà phiên bản chuẩn có.


2

Không. Hãy xem xét hai ví dụ này ở đây:

int multiply (int a, int b) {
   return a*b;
}

void multiply_void(int a, int b) {
   cout << a*b;
//or cout << multiply(a,b);
}

Hàm đầu tiên sẽ trả về một giá trị số nguyên có thể được sử dụng bởi một hàm khác. Giá trị được trả về và lưu trong bộ nhớ để sử dụng khi cần thiết. Nếu không, nó không được nhìn thấy cho con người và chỉ ngồi một cách hạnh phúc trong ký ức.

Chức năng thứ hai sẽ xuất ra thiết bị đầu ra mặc định (thường là bàn điều khiển). Giá trị được trả về bởi toán tử nhân được chuyển đến thiết bị đầu ra. Hàm Multi_void không trả về giá trị thực.


0

Tất cả các toán tử trả về một cái gì đó. Chúng được gọi là toán tử vì chúng vận hành một cái gì đó, do đó chúng sẽ trả về một cái gì đó. Những toán tử không trả về một cái gì đó không thể được gọi là toán tử. Chúng sẽ trả về một số giá trị hoặc trả về True hoặc False tùy thuộc vào tình huống.


0

Các nhà khai thác của riêng họ không nhất thiết phải trả lại bất cứ điều gì. Các cuộc gọi hàm trả về giá trị. Các toán tử có thể dẫn đến các giá trị. Các toán tử đôi khi có thể gọi các hàm. Những ví dụ bao gồm:

• Người điều hành cuộc gọi chức năng.

• Một toán tử quá tải được chuyển đổi thành một cuộc gọi hàm.

• toán tử mới, được gọi như một phần của biểu thức mới , là một lời gọi hàm.

Mục đích duy nhất của tôi khi đề cập đến lời gọi hàm là để làm rõ kết quả so với trả về. Dựa trên việc xem xét tất cả 126 trường hợp của “return” và các từ bắt nguồn từ nó trong [expr] , phần này dường như sử dụng cẩn thận từ return để chỉ:

• kết quả của một lệnh gọi hàm

• các khía cạnh của luồng kiểm soát liên quan đến các quy trình

OK, thế là đủ về kết quả so với lượt về.


0

Các toán tử C ++ trả về cái gì đó hay không phụ thuộc vào cách bạn sử dụng chúng. Các toán tử C ++ tích hợp trả về một số giá trị cho đến khi và trừ khi được thực thi để trả về giá trị vô hiệu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.