Toán tử cộng một bậc làm gì?


86

Toán tử cộng một bậc làm gì? Có một số định nghĩa mà tôi đã tìm thấy ( ở đâyđây ) nhưng tôi vẫn không biết nó sẽ được sử dụng để làm gì. Có vẻ như nó không làm gì cả nhưng đều có lý do của nó, phải không?


3
Tôi nghĩ rằng lý do lịch sử bị đánh giá thấp nghiêm trọng.
Wolf

3
Một câu hỏi với ba thẻ ngôn ngữ khác nhau là khá mơ hồ / không tốt! Các câu trả lời rất khác nhau đối với C # (có thể quá tải) và C (không có quá tải) và C ++ (có thể quá tải nhưng kế thừa điều này từ C và do đó các thuộc tính của nó cũng vậy).
Legends2k

Tôi muốn thêm một liên kết đến 10 sai sót hàng đầu của Eric Lippert về C #. Bạn sẽ tìm thấy toán tử cộng một bậc trong các đề cập danh dự: Informit.com/articles/article.aspx?p=2425867 Về cơ bản, ông ấy nói rằng nó nên được xóa hoặc không bao giờ được thêm vào.
Noel Widmer

Câu trả lời:


57

Nó sẽ bị quá tải nếu bạn cảm thấy cần thiết; đối với tất cả các loại được xác định trước, nó về cơ bản là không cần chọn.

Việc sử dụng thực tế của toán tử số học một bậc no-op khá hạn chế và có xu hướng liên quan đến hệ quả của việc sử dụng một giá trị trong một biểu thức số học, hơn là chính toán tử. Ví dụ, nó có thể được sử dụng để buộc mở rộng từ các loại tích phân nhỏ hơn inthoặc đảm bảo rằng kết quả của một biểu thức được coi là một giá trị và do đó không tương thích với một consttham số không tham chiếu. Tuy nhiên, tôi cho rằng những cách sử dụng này phù hợp hơn với mã chơi gôn hơn là tính dễ đọc. :-)


7
Điều này không thực sự đúng, như một số ví dụ dưới đây cho thấy.
jkerian

3
Được rồi, tôi sẽ mua rằng nó có một số cách sử dụng, nhưng hầu hết các cách sử dụng được thảo luận bên dưới liên quan đến thực tế là nó là một biểu thức số được xây dựng bằng cách sử dụng toán tử no-op: ví dụ: quảng cáo đến intvà dẫn đến một giá trị là hiệu ứng của biểu thức -ness, không phải của chính toán tử +.
Jeffrey Hantin

118

Trên thực tế, toán tử cộng không làm điều gì đó - ngay cả trong C. Nó thực hiện các chuyển đổi số học thông thường trên các toán hạng và trả về một giá trị mới, có thể là một số nguyên có chiều rộng lớn hơn. Nếu giá trị ban đầu là một số nguyên không dấu có độ rộng nhỏ hơn int, nó cũng sẽ được thay đổi thành một signedgiá trị.

Thường thì điều này không quan trọng lắm, nhưng nó có thể có ảnh hưởng, vì vậy không nên sử dụng cộng một bậc như một loại "nhận xét" biểu thị rằng một số nguyên dương. Hãy xem xét chương trình C ++ sau:

void foo(unsigned short x)
{
 std::cout << "x is an unsigned short" << std::endl;
}

void foo(int x)
{
 std::cout << "x is an int" << std::endl;
}

int main()
{
 unsigned short x = 5;
 foo(+x);
}

Điều này sẽ hiển thị "x là một số nguyên".

Vì vậy, trong ví dụ này, cộng một lần đã tạo ra một giá trị mới với kiểu và độ có dấu khác.


5
nếu bạn đang viết mã tạo ra kết quả nhất định khi cho một số ngắn và số nguyên so sánh bằng nhau, thì bạn có thể gặp phải vấn đề khác
Lie Ryan

1
Cảm ơn, mà làm cho nó rõ ràng (sidenote: Trong C, tôi không thể có được ví dụ để làm việc, kể từ khi tôi không thể quá tải chức năng foo)
Binarian

nó có nghĩa là gì khi nói an integer of greater width?
yekanchi

trong ngữ cảnh này, "chiều rộng" đề cập đến số byte bộ nhớ được liên kết với giá trị.
giles

41

Từ ấn bản thứ hai của K&R:

Đơn vị + là mới với tiêu chuẩn ANSI. Nó đã được thêm vào để đối xứng với một ngôi -.


6
Chắc chắn rồi. * Đây là lý do lịch sử. C ++ đã phải điều chỉnh nó, vì vậy nó phải đối phó với tình trạng quá tải.
Wolf

37

Tôi đã thấy nó được sử dụng để làm rõ ràng, để nhấn mạnh giá trị dương khác biệt với giá trị âm:

shift(+1);
shift(-1);

Nhưng đó là một cách sử dụng khá yếu. Câu trả lời chắc chắn là quá tải.


8
Tôi cũng đã làm điều này, đặc biệt là khi xử lý các vectơ nhưvec3(+1,-1,-1)
mpen

28

Một điều mà trình đơn nguyên tích hợp +làm là biến lvalue thành rvalue. Ví dụ, bạn có thể làm điều này

int x;
&x;

nhưng bạn không thể làm điều này

&+x;

:)

PS "Quá tải" chắc chắn không phải là câu trả lời đúng. Unary +được kế thừa từ C và không có quá tải toán tử cấp người dùng trong C.


14

Điều chính mà unary + đạt được là thăng hạng kiểu thành int cho các kiểu dữ liệu nhỏ hơn int. Điều này có thể khá hữu ích nếu bạn đang cố gắng in dữ liệu char bằng cách sử dụng std::coutdữ liệu số.

char x = 5;
std::cout << +x << "\n";

rất khác với

char x=5;
std::cout << x << "\n";

Nó cũng có sẵn cho quá tải, nhưng trong thực tế, quá tải của bạn sẽ được gần một NOP.


12

Nếu bạn cần in giá trị số của các byte thô (ví dụ: các số nhỏ được lưu trữ dưới dạng ký tự) để gỡ lỗi hoặc bất kỳ lý do gì, thì unary + có thể đơn giản hóa mã in. Xem xét

char c = 42;
cout << c << endl;           // prints "*\n", not what you want in this case
cout << (int)c << endl;      // prints "42\n", ok
cout << +c << endl;          // prints "42\n", much easier to type

Đây chỉ là một ví dụ nhanh. Tôi chắc chắn rằng có những lúc khác khi đơn vị + có thể giúp xử lý các byte của bạn giống số hơn thay vì giống văn bản.


4

Một mẩu tin lịch sử. Ủy ban tiêu chuẩn hóa C99 cũng cho rằng việc sử dụng hiện tại của cộng một bậc là khá hiếm, bằng chứng là họ đang cân nhắc sử dụng lại nó để đạt được một tính năng khác trong ngôn ngữ: hạn chế đánh giá thời gian dịch của các biểu thức hằng dấu phẩy động. Xem phần trích dẫn sau đây từ Cơ sở lý luận C, phần F.7.4:

Phiên bản đầu tiên của thông số kỹ thuật này cho phép số học hằng số thời gian dịch, nhưng trao quyền cho toán tử một ngôi +, khi được áp dụng cho một toán hạng, để hạn chế đánh giá thời gian dịch của các biểu thức hằng số.

Cuối cùng, ngữ nghĩa đã bị đảo ngược, với đánh giá thời gian chạy được thực thi trong hầu hết các ngữ cảnh (ít nhất là theo quy tắc "như thể") và khả năng thực thi đánh giá thời gian dịch bằng cách sử dụng trình khởi tạo tĩnh. Lưu ý rằng sự khác biệt chính nằm ở việc xuất hiện các ngoại lệ dấu chấm động và các cài đặt độ chính xác hoặc làm tròn dấu chấm động khác, nếu có.


3

Không nhiều. Lập luận chung cho việc cho phép quá tải operator+()là chắc chắn có những cách sử dụng trong thế giới thực để quá tải operator-()và sẽ rất kỳ lạ (hoặc không đối xứng) nếu bạn cho phép quá tải operator-()nhưng không operator+().

Tôi tin rằng lần đầu tiên tôi đọc lập luận này từ Stroustrop, nhưng tôi không có sách bên mình để xác minh nó. Tôi có thể sai.


3

Unary plus đã có mặt trong C, nơi nó hoàn toàn không làm gì cả (giống như autotừ khóa). Để không có nó, Stroustrup sẽ phải đưa ra một chất không tương thích vô cớ với C.

Một khi nó ở trong C ++, tự nhiên cho phép một hàm quá tải, giống như hàm trừ một bậc, và Stroustrup có thể đã giới thiệu nó vì lý do đó nếu nó chưa có ở đó.

Vì vậy, nó không có nghĩa là gì. Nó có thể được sử dụng như một loại trang trí để làm cho mọi thứ trông đối xứng hơn, sử dụng +1,5 làm đối diện với -1,5 chẳng hạn. Trong C ++, nó có thể bị quá tải, nhưng sẽ rất khó hiểu nếu operator+()làm bất cứ điều gì. Hãy nhớ quy tắc tiêu chuẩn: khi nạp chồng các toán tử số học, hãy làm những việc như cách intlàm.

Nếu bạn đang tìm kiếm lý do tại sao nó ở đó, hãy tìm điều gì đó về lịch sử ban đầu của C. Tôi nghi ngờ không có lý do chính đáng, vì C không thực sự được thiết kế. Hãy xem xét autotừ khóa vô dụng (có lẽ là trái ngược với static, hiện đang được tái chế trong C ++ 0x) và entrytừ khóa không bao giờ làm bất cứ điều gì (và sau đó bị bỏ qua trong C90). Có một email nổi tiếng, trong đó Ritchie hoặc Kernighan nói rằng, khi họ nhận ra quyền ưu tiên của nhà điều hành có vấn đề, đã có ba bản cài đặt với hàng nghìn dòng mã mà họ không muốn phá vỡ.


1
Sự quá tải phi số học duy nhất mà tôi đã thấy có ý nghĩa là trong các biểu thức chính quy hoặc ngữ pháp trong đó (+ hạn) có nghĩa là một hoặc nhiều tem. (Đó là khá chuẩn cú pháp biểu thức chính quy)
Michael Anderson

Giới thiệu entry: ( stackoverflow.com/q/254395/153285 ). Ngày nay, nếu bạn muốn có nhiều điểm đầu vào, chỉ cần sử dụng lệnh gọi đuôi và tối ưu hóa hướng dẫn hồ sơ.
Potatoswatter

Tôi tin rằng ngay cả trong C99, đã cho extern volatile int foo;, một trình biên dịch đưa ra tuyên bố +foo;sẽ được yêu cầu thực hiện đọc địa chỉ được chỉ định trên bất kỳ nền tảng nào có thể tồn tại bất kỳ phương tiện nào để xác định rằng quá trình đọc đã diễn ra. Tôi không chắc điều đó sẽ được yêu cầu nếu câu lệnh chỉ là "foo", mặc dù nhiều trình biên dịch sẽ làm điều đó như một phép lịch sự.
supercat

2

Tôi không thể trích dẫn bất kỳ nguồn nào cho điều này, nhưng tôi hiểu rằng nó là để quảng cáo kiểu rõ ràng, ngụ ý chuyển đổi kiểu không mất dữ liệu. Điều đó đặt nó ở đầu hệ thống phân cấp chuyển đổi,

  • Khuyến mãi: new_type operator+(old_type)
  • Chuyển đổi: new_type(old_type)
  • Diễn viên: operator(new_type)(old_type)
  • Cưỡng chế: new_type operator=(old_type)

Tất nhiên, đó là từ cách giải thích của tôi về một ghi chú trong một trong những sách hướng dẫn c / c ++ của microsoft (thực sự cũ) mà tôi đã đọc khoảng 15 năm trước, vì vậy hãy coi nó như muối bỏ bể.


1
#include <stdio.h>
int main()
{
    unsigned short x = 5;
    printf ("%d\n",sizeof(+x)); 
    printf ("%d\n",sizeof(x)); 
    return 0;
}

Như thể hiện trong ví dụ trên, đơn vị + thực sự thay đổi kiểu, kích thước 4 và 2 tương ứng. Kỳ lạ là biểu thức + x thực sự được tính bằng sizeof, tôi nghĩ điều đó không nên. Có lẽ đó là do sizeof có cùng mức độ ưu tiên với dấu +.


-1

Tôi cho rằng bạn có thể sử dụng nó để luôn tạo ra một số dương. Chỉ cần nạp chồng toán tử đơn vị + thành abs. Không thực sự đáng để các nhà phát triển đồng nghiệp của bạn bối rối, trừ khi bạn thực sự chỉ muốn làm xáo trộn mã của mình. Sau đó, nó sẽ hoạt động tốt.


Điều đó sẽ làm cho nó không đối lập với trừ một bậc sẽ gây nhầm lẫn, trừ khi bạn cũng quá tải trừ một bậc thành một cơ số âm, điều này sẽ làm cho tất cả các loại toán học trở nên tồi tệ hơn
Davy

Uhh, vâng. Đó là lý do tại sao tôi đề nghị không làm điều đó.
Patrick

1
@ Davy8: Điều gì khiến bạn nghĩ cộng một bậc hiện là "đối lập" với trừ một bậc? "Ngược lại" của toán tử bổ sung bitwise là ~gì? Tôi không chắc định nghĩa của bạn về "đối nghịch" là gì, nhưng tôi nghi ngờ nó bị sai lệch theo kinh nghiệm về những gì cộng một và trừ một bậc hiện đang làm.
ndkrempel

-1

CHỈNH SỬA Đã viết lại hoàn toàn, bởi vì tôi đã bỏ qua câu trả lời ban đầu của mình.

Điều này sẽ cho phép bạn xử lý khai báo rõ ràng về kiểu của bạn dưới dạng giá trị dương (tôi nghĩ hầu hết là trong các phép toán phi toán học). Có vẻ như phủ định sẽ hữu ích hơn, nhưng tôi đoán đây là một ví dụ về nơi nó có thể tạo ra sự khác biệt:

public struct Acceleration
{
    private readonly decimal rate;
    private readonly Vector vector;

    public Acceleration(decimal rate, Vector vector)
    {
        this.vector = vector;
        this.rate = rate;
    }

    public static Acceleration operator +(Acceleration other)
    {
        if (other.Vector.Z >= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public static Acceleration operator -(Acceleration other)
    {
        if (other.Vector.Z <= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public decimal Rate
    {
        get { return rate; }
    }

    public Vector Vector
    {
        get { return vector; }
    }
}

Đó không phải là một hoạt động một lần đối với tôi. Nó cần hai đối số (tháng 4 và tháng 5) để nó là nhị phân.
BlueMonkMN

Đó là cộng nhị phân. Cộng một bậc chỉ là "+1" hoặc một số tương tự, không có toán hạng bên trái.
Jeffrey Hantin

lỗi của tôi. quên CS101 của tôi. đã sửa.
Michael Meadows

3
Nếu tôi phát hiện thấy loại quá tải đó trong mã sản xuất, tôi chắc chắn sẽ đánh dấu nó là lỗi và sửa nó càng sớm càng tốt. Ngữ nghĩa của +không phải để làm cho một giá trị dương, nhưng để giữ nguyên dấu hiệu của nó.
Arturo Torres Sánchez

-1

chỉ đơn giản là dùng để thuyết phục những con số nào là tích cực

ví dụ;

int a=10;
System.out.println(+x);// prints 10(that means,that number 10 multiply by +1,{10*+1})

//if we use unary minus

int a=10;
System.out.println(-x);//prints -10(that means,that number 10 multiply by +1,{10*-1})
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.