Kelebihan dalam C ++. Bagian II Operator Kelebihan



Kami melanjutkan seri "C ++, menggali lebih dalam." Tujuan dari seri ini adalah untuk memberi tahu Anda sebanyak mungkin tentang berbagai fitur bahasa, mungkin sangat istimewa. Artikel ini membahas tentang kelebihan operator. Perhatian khusus diberikan pada penggunaan operator kelebihan beban di perpustakaan standar. Ini adalah artikel kedua dalam seri ini, yang pertama didedikasikan untuk fungsi dan templat yang berlebihan, ada di sini . Artikel selanjutnya akan fokus pada pernyataan manajemen memori yang berlebihan.



Daftar Isi


Daftar Isi

  
  1.
    1.1.
    1.2.
    1.3. ,
    1.4.
    1.5.
      1.5.1.
      1.5.2.
      1.5.3.
  2.
    2.1.
    2.2.
      2.2.1.
      2.2.2.
      2.2.3.
      2.2.4.
    2.3.
    2.4.
    2.5.
    2.6.
  3.
    3.1. ->
    3.2. *
    3.3. []
      3.3.1.
    3.4. ()
      3.4.1. -
      3.4.2.
      3.4.3. -
      3.4.4.
      3.4.5.
      3.4.6.
      3.4.7.
    3.5.
    3.6.
    3.7. ,
    3.8. << >>
    3.9.
    3.10. !
  4.
  
     .
     . - C-
  




pengantar


Overloading operator adalah kemampuan untuk menerapkan operator bahasa bawaan untuk berbagai jenis, termasuk jenis pengguna. Sebenarnya, ini adalah ide yang cukup lama. Sudah dalam bahasa-bahasa pemrograman pertama, simbol dari operasi aritmatika: +.-, dll. digunakan untuk operasi pada bilangan bulat dan bilangan real, meskipun faktanya mereka memiliki ukuran yang berbeda dan representasi internal yang berbeda, dan oleh karena itu, operasi ini dilaksanakan dengan cara yang berbeda. Dengan munculnya bahasa-bahasa berorientasi objek, ide ini dikembangkan lebih lanjut. Jika operasi pada tipe yang ditentukan pengguna memiliki semantik yang serupa dengan operasi pada tipe built-in, maka mengapa tidak menggunakan sintaks dari operator built-in. Ini dapat meningkatkan keterbacaan kode, membuatnya lebih ringkas dan ekspresif, menyederhanakan penulisan kode umum. Dalam C ++, operator overloading memiliki dukungan serius dan secara aktif digunakan di perpustakaan standar.



1. Masalah umum kelebihan operator



1.1. Operator yang kelebihan beban


C++17 : +, -, *, /, %, ^, &, |, ~, !, ,, =, <, >, <=, >=, ++, –-, <<, >>, ==, !=, &&, ||, +=, -=, /=, %=, ^=, &=, |=, *=, <<=, >>=, [], (), ->, ->*, new, new[], delete, delete[].
( , C++98.) , , , . , (), . +, -, *, &, ++, –- ( ) — , , 6 .



1.2.


, . — + += std::basic_string<>. std::filesystem::path (C++17). / /= . , . .


, . — << . , , , .


std::out<<c?x:y;



(std::out<<c)?x:y;



std::out<<(c?x:y);

.


std::out void*, - . -, , . += , , , , .



1.3. ,


: , (), &&, ||. , ( ), (short-circuit evaluation), , . ( , , , && , false, || , true.)


& ( ). & , . ++11 ( ) std::addressof(), & .



1.4.


. , . , , . , , , . , , . a=b=c. bool . +, -, ~ . , . , , ( . [Sutter1]). , , . .



1.5.



1.5.1.


: - (-) . - — =, ->, [], (). .


, - - operator@, @ () . , . () .


, (-) , operator@, @ () . , , . — , ( ), , . , , . :


namespace N
{
    class X
    {
    // ...
        X operator+() const;           //  
        X operator+(const X& x) const; //  
        void operator()(int x, int y); //  
        char operator[](int i);        // 
    };
    X operator-(const X& x);             //  
    X operator-(const X& x, const X& y); //  
}

, , -, .



1.5.2.


(): . .


( , N):


N::X x, y;
//  
N::X z = x + y;
N::X v = x – y;
N::X w = +x;
N::X u = -x;
x(1,2);
char p = x[4];
//  
N::X z = x.operator+(y);
N::X v = operator-(x, y);
N::X w = x.operator+();
N::X u = operator-(x);
x.operator()(1,2);
char p = x.operator[](4);

, , , . , , . ( ) , . ( — .) -> , , .


, , (argument depended lookup, ADL), , , , , , . , ADL .



1.5.3.


, , - . . , , . . , . , .



2.



2.1.


. — const ( -), ( ). () .


std::string + : const std::string&, const char*.


3.4.2 ().


() , .



2.2.


, , , .



2.2.1.


— . , x@y, y@x . , - . + std::string, const char*.



2.2.2.


-. (, -, .) . -, , , -, . . 3.8.



2.2.3.


— . X , , X. , . , -, . .


int i = 42;
std::reference_wrapper<int> rwi(i);
std::cout << rwi << '\n'; // : 42

std::reference_wrapper<int>, int&, . , , . , 2.3.



2.2.4.


, -, . 2.6.



2.3.


, , . , .


class X
{
// ...
    friend X operator+(const X& x, const X& y) //  
    {
    // ...
    }
};

. , , , . , . , [Meyers1]. + friend, - .


// rational number ( )
template<typename T>
class Rational 
{
    T num; // numerator ()
    T den; // denominator ()
public:
    Rational(T n = 0, T d = 1) : num(n), den(d) {/* ... */}

    T Num() const { return num; }
    T Den() const { return den; }

    friend const Rational operator+(
        const Rational& x, const Rational& y)
    {
        return Rational(
                x.num * y.den + y.num * x.den,
                x.den * y.den);
    }
};
template<typename T>
const Rational<T>operator-(
    const Rational<T>& x, const Rational<T>& y)
{
    return Rational<T>(
        x.Num() * y.Den() - y.Num() * x.Den(), 
        x.Den() * y.Den());
}

+ . , T Rational, . :


Rational<int> r1(1, 2), r2(31, 64);
Rational<int> r3 = r1 + r2; // Rational + Rational
Rational<int> r4 = r1 + 3;  // Rational + int
Rational<int> r5 = 4 + r2;  // int + Rational

Rational int. int int Rational, .


-.


Rational<int> r6 = r1 - 3; // Rational - int
Rational<int> r7 = 4 - r2; // int - Rational

, int Rational . , , -:


template<typename T>
const Rational<T> operator-(const Rational<T>& x, T y)
{
    return operator-(x, Rational<T>(y));
}

template<typename T>
const Rational<T> operator-(T x, const Rational<T>& y)
{
    return operator-(Rational<T>(x), y);
}

. [Meyers1].



2.4.


, , (computational constructor). (return value optimization, RVO). . [Dewhurst].



2.5.


-, . , , ( NVI – non virtual interface). «» . . , , *a+*b. , ( +), , ( Visitor). , , . [Dewhurst]. . , , — .



2.6.


, , . :


enum class Color { Begin, Red = Begin, Green, Blue, End};
//  
Color& operator++(Color& col) { return (Color&)(++(int&)col); }

:


void Foo(Color col);
// ...
for (Color col = Color::Begin; col < Color::End; ++col)
{
    Foo(col);
}



Color operator*(Color col) { return col; }

:


std::for_each(Color::Begin, Color::End, Foo);

. :


struct Colors
{
    Color begin() const { return Color::Begin; }
    Color end() const { return Color::End; }
};

for:


for (auto col : Colors())
{
    Foo(col);
}


3.


, .



3.1. ->


- ( ). (, ), , ->. «» — . :


class X
{
// ...
    void Foo();
};
class XPtr
{
// ...
    X* operator->() const;
};
// ...
X x;
x->Foo();              //  
x.operator->()->Foo(); //  

-> .



3.2. *


->. , , ->. -.


* .



3.3. []


, , , -, . , , , . «» , , . . , , , , &[i], . , , .


— .


T& operator[](int ind);
const T& operator[](int ind) const;

, -.


std::vector<>, std::array<>, std::basic_string<>, std::deque<> std::map<>, std::unordered_map<>. std::unique_ptr<> .



3.3.1.


C++ , a[i,j] , « », a[i][j]. -. .


template<typename T>
class Matrix
{
public:
    Matrix(int rowCount, int colCount);

    class RowProxy;
    RowProxy operator[](int i) const;

    class RowProxy
    {
    public:
        T& operator[](int j);
        const T& operator[](int j) const;
        // ...
    };
    // ...
};
// ...
Matrix<double> mtx(5, 6);
double s = mtx[1][2];
mtx[2][3] = 3.14;


3.4. ()


-. , . , (), , . C++ . C++ . , , : , , -, , . , . , , ( ), () -. — std::for_each(), .



3.4.1. -


C++ ( ). . - « ».



3.4.2.


(), . . .



3.4.3. -


( std::unordered_set<>, std::unordered_multiset<>, std::unordered_map<>, std::unordered_multimap<>) , - . -. () - std::size_t. , . std::hash<>, . , . , , -. .


  1. .
  2. .

C- .



3.4.4.


, . . () , , bool. , . std::less<> std::equal_to<>, . <, ==.


std::less<> std::set<>, std::multiset<>, std::map<>, std::multimap<>, std::priority_queue<>.


std::equal_to<> std::unordered_set<>, std::unordered_multiset<>, std::unordered_map<>, std::unordered_multimap<>.


, .


  1. , . , , , , ( ).
  2. , .
  3. .

C- .



3.4.5.


, . , (deleter). () . std::unique_ptr<> std::default_delete<>, delete ( delete[] ). std::shared_ptr<> delete. , . .


  1. std::unique_ptr<> -.
  2. .

- std::shared_ptr<>, std::shared_ptr<>.



3.4.6.


, , . , ( ), .


Jika objek fungsional yang diperlukan tidak ditentukan, operator <digunakan secara default dalam algoritma std::lexicographical_compare()yang membandingkan rentang, dalam algoritma pencarian minimum / maksimum ( min_element(), dll), dalam algoritma yang terkait dengan pengurutan dan pengurutan data ( std::sort(), dll), dalam algoritma terkait piramida ( std::make_heap(), dll).

Operator ==digunakan secara default dalam algoritma std::equal()yang membandingkan rentang, dalam algoritma std::count()yang menghitung jumlah elemen tertentu, dalam algoritma pencarian ( std::find(), dll), dalam algoritma std::replace()dan std::remove()yang memodifikasi rentang.


Operator +digunakan secara default dalam algoritma accumulate(). (Untuk perinciannya, lihat Lampiran A.)


, .


  1. , . , .
  2. , . ( -.)

C- .



3.4.7.


C++11 . () . , - . .


#include <functional>

int Foo(const char* s) { return *s; }

struct X
{
    int operator() const (const char* s) { return *s; }
};

std::function<int(const char*)>
    f1 = Foo,
    f2 = X(),
    f3 = [](const char* s) { return *s; };

int r1 = f1("1"),
    r2 = f2("2"),
    r3 = f3("3");


3.5.


. bool.


< ==, . . (. [Josuttis]). < : ( x<y true, y<x false), ( x<y y<z, x<z), (x<x false), ( !(x<y) && !(y<x) !(y<z) && !(z<y), !(x<z) && !(z<x)). == : ( x==y, y==x), ( x==y y==z, x==z), (x==x true). , . , .

. . < ==, !. , . std::rel_ops <=, >, >=, !=. ( <utility>.) .


#include <utility>

class X { /* ... */ };
//  
bool operator==(const X& lh, const X& rh);
bool operator<(const X& lh, const X& rh);
//  
bool operator<=(const X& lh, const X& rh)
{
    return std::rel_ops::operator<=(lh, rh);
}
//   

, std::rel_ops , using-:


using namespace std::rel_ops;

<, <=, >, >=, ==, !=, , : std::thread::id, std::type_index, std::monostate. , , . .


== != std::error_code, std::bitset. , < .



3.6.


, + +=. , — -. , +, -, -. .


class X
{
// ...
    const X operator-() const; //  
    X& operator+=(const X& x); //  
};
const X operator+(const X& x, const X& y); //  

+, - ( ) . . , , . -, *this. + += , 1.4.1, , X , const .


. C-, . (. 2.2).


std::complex<>. +, +=, -, -= . std::basic_string<> + += . std::filesystem::path (C++17). / /= . , . .




3.7. ,


. , . - . .


class Iter
{
public:
    Iter& operator++() //  
    {
        //  
        return *this;
    }

    const Iter operator++(int) //  
    {
        Iter it(*this);
        ++*this;
        return it;
    }
    // ...
};

, , , . 1.4.


, .



3.8. << >>


( ). , : , , . .


#include <iostream>

struct Point
{
    int X;
    int Y;
};
std::ostream& operator<<(std::ostream& strm, const Point& p)
{
    strm << '[' << p.X << ',' << p.Y << ']';
    return strm;
}

— , , . void*, - . . 1.2.



3.9.


, -, . , , , . / . , . — . « », , ( ), , .


— , .



class X
{
public:
    X(const X& src);     //  
    X(X&& src) noexcept; //  

    X& operator=X(const X& src);     //   
    X& operator=X(X&& src) noexcept; //   
// ...
};

, , . - noexcept.


. "=default".


class X
{
public:
    X& operator=X(const X& src) = default;
    X& operator=X(X&& src) = default; 
// ...
};

. , , .


class X
{
public:
    X& operator=X(const X& src) = delete;
    X& operator=X(X&& src) = delete; 
// ...
};

. , *this. , a=b=c. — « ». - , .


class X
{
public:
    void Swap(X& src) noexcept;     //  
    X(const X& src);                //  
    X(X&& src) noexcept;            //  
    X& operator=X(const X& src);
    X& operator=X(X&& src) noexcept;
// ...
};

:


X& X::operator=X(const X& src)
{
    X tmp(src); // 
    Swap(tmp);
    return *this;
}
X& X::operator=X(X&& src) noexcept
{
    X tmp(std::move(src)); // 
    Swap(tmp);
    return *this;
}

, .
: , , ( ).



« » , .


X& X::operator=X(const X& src)
{
    if (this != std::addressof(src))
    {
        // ...
    }
    return *this;
}

, , . « » , , , , .


, , .


X& X::operator=X(const X& src)
{
    if (this != std::addressof(src))
    {
        this->~X();
        new (this)(src);
    }
    return *this;
}

this, new , this, . , , , . , , this, , . . , X - X . this->~X() , . .


( ) , /. ( .) , . .



3.10. !


, . true, («», «»). . explicit bool, , true, .


explicit operator bool() const noexcept;


4.


. , .


.





.


std::variant<> (C++17). std::visit() , () std::variant<>, . std::visit() () , std::variant<>. .


using IntStr = std::variant<int, std::string>;

struct Visitor
{
    void operator()(int x) const
    { 
        std::cout << "int, val=" << x << '\n';
    }
    void operator()(const std::string& x) const
    {
        std::cout << "string, val=" << x << '\n';
    }
};
// ...
IntStr a(42), b("meow");
Visitor v;
std::visit(v, a); // : int, val=42
std::visit(v, b); // : string, val=meow

std::reduce() (C++17). std::accumulate(). std::accumulate().


template<class InputIt, class T, class BinOper>
T accumulate(InputIt first, InputIt last, T init, BinOper oper);

BinOper — ,


T f(T t, S s);

T — , S — , T. , , T S , . , , . init. , C++17 std::reduce(), , .


template<class ExecutionPolicy,
    class InputIt, class T, class BinOper>
T reduce(ExecutionPolicy&& policy,
    InputIt first, InputIt last, T init, BinOper oper);

BinOper std::accumulate() — , BinOper :


T f(T t, S s);
T f(S s1, S s2);
T f(T t1, T t2);


. - C-


C- — , — T* const T*, T (char, wchar_t, etc). std::hash<>, std::less<> std::equal_to<> , , . .


#include <functional>

template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + 
        (seed << 6) + (seed >> 2);
}

#include <cstring>

namespace std
{
    template <>
    struct hash<const char*>
    {
        size_t operator()(const char* str) const
        {
            std::size_t hash = 0;
            for (; *str; ++str)
            {
                hash_combine(hash, *str);
            }
            return hash;
        }
    };

    template <>
    struct equal_to<const char*>
    {
        bool operator()(const char* x, const char* y) const
        {
            return strcmp(x, y) == 0;
        }
    };

    template <>
    struct less<const char*>
    {
        bool operator()(const char* x, const char* y) const
        {
            return strcmp(x, y) < 0;
        }
    };
} // namespace std

hash_combine() — Boost. -.


, , C- - .


#include <cstring>
const char* cc[] = { "one", "two", "three", "four" };

std::sort(cc, cc + _countof(cc),
    [](const char* x, const char* y)
        { return std::strcmp(x, y) < 0; });



[Josuttis]
Josattis, Nikolai M. C ++ Perpustakaan Standar: Panduan Referensi, edisi kedua: Per. dari bahasa Inggris - M.: LLC “Saya. Williams ", 2014.
[Dewhurst]
Dewhurst, Stefan K. Slippery menempatkan C ++. Cara menghindari masalah saat merancang dan menyusun program Anda: Per. dari bahasa Inggris - M .: DMK Press, 2012.
[Meyers1]
Meyers, Scott. Penggunaan C ++ secara efektif. 55 cara pasti untuk meningkatkan struktur dan kode program Anda:: Per. dari bahasa Inggris - M .: DMK Press, 2014.
[Sutter1]
Sutter, Lambang. Solusi masalah kompleks dalam C ++.: Per. dari bahasa Inggris - M: LLC “Saya. Williams, 2015.


All Articles