Kelebihan dalam C ++. Bagian I. Fungsi dan template kelebihan beban


C ++ adalah bahasa yang kompleks dan menarik, Anda dapat meningkatkan hampir semua kehidupan Anda di dalamnya. Pada titik tertentu, saya ingin mempelajarinya sebagai berikut: mengambil beberapa aspek bahasa, mungkin sangat sempit, dan menanganinya sedalam dan sedetail mungkin. Pendekatan ini sebagian besar didorong oleh buku-buku luar biasa Scott Meyers, Herb Sutter, dan Stephen Dewhurst. Ketika sejumlah materi telah menumpuk, saya memutuskan untuk memperkenalkan Khabrovchan kepada mereka. Jadi ada seri ini, yang saya sebut "C ++, menggali lebih dalam." Serial ini ditandai sebagai Tutorial, tetapi masih fokus bukan pada pemula, melainkan pada tingkat menengah. Topik pertama adalah overloading di C ++. Topiknya ternyata sangat luas dan kami mendapat tiga artikel. Artikel pertama adalah tentang kelebihan fungsi dan template, yang kedua adalah operator yang kelebihan beban dan yang ketiga adalah operator yang kelebihan bebannew/delete. Jadi, mari kita mulai menggali.



Daftar Isi


Daftar Isi

  
  1.
    1.1.
    1.2.
    1.3.
      1.3.1.
      1.3.2.
      1.3.3.
    1.4.
      1.4.1. using-
      1.4.2. using-
      1.4.3. using-
      1.4.4. ,
  2.
    2.1. «»
    2.2.
    2.3.
    2.4.
    2.5.
      2.5.1.
      2.5.2. SFINAE
      2.5.3.
      2.5.4.
    2.6. «»
      2.6.1. ,
      2.6.2. Rvalue
      2.6.3.
  3. ,
    3.1.
    3.2.
    3.3.
    3.4.
    3.5.
  4.
  
     . Visitor
     .
  




pengantar


Dalam arti luas, overloading adalah kemampuan untuk secara bersamaan menggunakan beberapa fungsi dengan nama yang sama. Kompiler membedakan mereka karena mereka memiliki set parameter yang berbeda. Pada titik panggilan, kompiler menganalisa jenis argumen dan menentukan fungsi tertentu yang harus dipanggil. Dalam literatur berbahasa Rusia, istilah "berbagi" kadang-kadang dapat ditemukan, tetapi tampaknya tidak berakar.


Overloading didukung oleh banyak bahasa pemrograman, kami hanya akan mempertimbangkan C ++ 17.



1. Ketentuan Umum



1.1. Fungsi Kelebihan Beban


( ) (overloaded), (scope) . , (=delete) .


void Foo();
char Foo(); // 
void Foo(int x);
void Foo(int x) noexcept;  // 
void Foo(double x);
void Foo(double) = delete; // 

, .


, . (decay) ,


void Foo(int x[4]);
void Foo(int x[]);
void Foo(int *x);

, .


.


, , const ( volatile),


void Foo(int x);
void Foo(const int x);

, .



1.2.


. (lookup) , (candidate functions). (template argument deduction). ( ). , . , . , , , « » (match the arguments most closely). (overload resolution). , , (ambiguous call to overloaded function). :


void Foo(float x);
void Foo(double x);

Foo("meow") , Foo(42) , , Foo(3.14f) Foo(3.14) .


(overload resolution rules) ( , ), , . .


« » : - . .


— . ( private protected). ( =delete). , . , , .



1.3.


, . . , . . , , , . () .


, . . , . , , . (hide) . , , , , , .



1.3.1.


, , . .


class X {/* ... */};
// ...
X x;
x.Foo();
X::Foo(42);

X. X.


namespace N {/* ... */}
// ...
N::Foo();

N, .


::Foo();

, .


«» .


, , .


( ), , .




{
    Foo();
}

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



1.3.2.


.


class B
{
// ...
public:
    void Foo(int x);
};

class D : public B
{
// ...
public:
    D();
    void Foo(double x);
};
// ...
D d;
d.Foo(42);

Foo, ? D::Foo(double), B::Foo(int) . ( D), , ( B) . D::Foo(double) . D::Foo(double) , , B::Foo(int) , . , D Foo, B B::Foo(int).


. C++ , , . . , . ( , .)



1.3.3.


C++, . ( ), :


{
    void Foo();
    void Foo(int x);
// ...
    Foo(42);
// ...
}

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



1.4.


using- using-. , , .


, , , , , .



1.4.1. using-


:


class B
{
// ...
public:
    void Foo(int x);
};
class D : public B
{
// ...
public:
    using B::Foo;
    void Foo(double x);
};
// ...
D d;
d.Foo(42);

Foo B, B::Foo(int).



1.4.2. using-


using- , . using- . , , using-, , . :


namespace N
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
void Test()
{
    using N::Foo; //  Foo(const char*)
    Foo(42);      // OK, N::Foo(int x)
    Foo("meow");  // , Foo(const char*) 
}

, Foo , using- :


namespace N
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
using N::Foo;
void Test()
{
    Foo(42);      // OK, N::Foo(int)
    Foo("meow");  // OK, Foo(const char*)
}


1.4.3. using-


N.


using namespace N;

using-. N N::. N, using- (, using-, ). , , using- , .


, , , , . ( using-.)


namespace
{
    void Foo(int x);
}

void Foo(const char* x);
// ...
Foo(42);     // OK, Foo(int),   
Foo("meow"); // OK, Foo(const char*)


1.4.4. ,


, . :


namespace N
{
    class X {/* ... */};
    void Foo(const X& x);
}

( N):


N::X x;
Foo(x);

N , , N::Foo(const X&). , (argument depended lookup, ADL), . ADL , .



2.


, .



2.1. «»


C++ . , . , , . : , , .


bool. bool int bool. . bool int.


void Foo(int x);
void Foo(bool x);
// ...
int x = 6, y = 5;
Foo(x == y); // Foo(bool)
Foo(x = y);  // Foo(int)



void Foo(bool x, int y);
void Foo(int x, bool y);

, :


Foo(1, 2);

, . int.


enum Qq { One = 1, Two };
void Foo(int x);
void Foo(Qq x);
// ...
Foo(One); // Foo(Qq)
Foo(42);  // Foo(int)

, , int long .


void Foo(int x);
void Foo(long x);
// ...
Foo(42);  // Foo(int)
Foo(42L); // Foo(long)

. . , , . :


void Foo(long x);
void Foo(long long x);

void Foo(float) = delete;
void Foo(double) = delete;
void Foo(long double) = delete;


2.2.


C++11 — std::nullptr_t nullptr. .


void Foo(int x);
void Foo(void* x);
// ...
Foo(0);       // Foo(int)
Foo(nullptr); // Foo(void*)

C++98


Foo((void*)0);

. nullptr , nullptr.


void Foo(void* x);
void Foo(std::nullptr_t);
// ...
void* x = nullptr;
Foo(x);       // Foo(void*)
Foo(nullptr); // Foo(std::nullptr_t)

.



2.3.


++11 (uniform initialization) — std::intializer_list<>. , , . . .


  1. {}, . , .
  2. , std::intializer_list<>. std::intializer_list<>, , . , std::intializer_list<>, ( ), .

std::vector<T>, std::intializer_list<T>.


:


std::vector<int> v1(3, 1), v2{3, 1};

v1 — 3 1. v2 — 2 3 1, std::intializer_list<int>, , .


:

std::vector<const char*> u1(3, "meow"), u2{3, "meow"};

u1 u2 , 3. u2 std::intializer_list<const char*> , u1.


:


std::vector<bool> b1(3, true), b2{3, true};

b1 3 , true. b2 , std::intializer_list<bool> int bool.


[Meyers2].



2.4.


, ... , , . .



2.5.


, , . — c .


. ( , ), .



2.5.1.


. , . , . , .


, , . , . , , . [Sutter2].


C++11 (variadic templates). , , , .



2.5.2. SFINAE


, , . :


template<typename T>
void Foo(const T* x);
// ...
Foo(42);

, , , , , «» . SFINAE, Substitution Failure is not an Error ( ).



2.5.3.


, .


void Foo(int x); //  
template<typename T>
void Foo(T x); //  1
template<>
void Foo<double>(double x); //    1  double
template<>
void Foo<const char*>(const char* x); //    1  const char*
template<typename T>
void Foo(const T* x); //  2,     1
template<typename T>
class U {/* ... */};
template<typename T>
void Foo(U<T> u); //  3,     1

, :


Foo(42);       // #1 —  
Foo(3.14);     // #2 —    1  double
Foo(42L);      // #3 —   1  long
Foo("meow");   // #4 —   2  char
Foo(U<int>()); // #5 —   3  int

: 1 int. .


, double int. : 1 double 1 double, .


, long int. : 1 long, .


, : 1 const char* 2 char. 2 , , 1 const char* .


, : 1 U<int> 3 int. 3 .



2.5.4.


:


void Foo(int x);     //  
template<typename T> // 
void Foo(T x);

int, int&, const int, const int&, (long, short, unsigned int, etc.) . , (greedy). , , , . . , . — (template disabling). :


template<
    typename T,
    typename S = std::enable_if_t<!std::is_integral<T>::value>>
void Foo(T x);

SFINAE , , .


, , , :


template<typename T> //  
void FooInt(T x);
template<typename T> //  
void FooEx(T x);
// C++17
template<typename T>
void Foo(T x)
{
    if constexpr (std::is_integral<T>::value)
    {
        FooInt(x);
    }
    else
    {
        FooEx(x);
    }
}
// C++11
template<typename T>
void Foo(T x)
{
    std::is_integral<T>::value
        ? FooInt(x)
        : FooEx(x);
}

<type_traits>.



2.6. «»


«» : , , , rvalue .


. :


  1. lvalue — ;
  2. () lvalue — ;
  3. rvalue — lvalue, std::move();
  4. () rvalue — .

— .


, .
:


void Foo(T& x);

lvalue.


rvalue-:


void Foo(T&& x);

rvalue.


:


void Foo(const T& x);
void Foo(T x);

.



2.6.1. ,


:


void Foo(T& x);
void Foo(const T& x);

lvalue ( ), .


:


void Foo(T& x);
void Foo(T x);

rvalue , lvalue .


:


void Foo(const T& x);
void Foo(T x);

.


- const this.


class X
{
public:
    X();
    void Foo();       // this   X*
    void Foo() const; // this   const X*
    void DoSomething() const;
    void DoSomethingElse();
// ...
};
void X::DoSomething() const
{
// ...
    Foo(); // Foo() const
// ...
}
void X::DoSomethingElse()
{
// ...
    Foo(); // Foo()
// ...
}
// ...
X x;
x.Foo();  // Foo()
const X cx;
cx.Foo(); // Foo() const

H - rvalue , rvalue. rvalue .


class X
{
public:
    X();
    void Swap(X& other) noexcept;
// ...
};
// ...
X x;
// ...
X().Swap(x); // OK
x.Swap(X()); // ,      

rvalue . , . rvalue . ( , rvalue .) rvalue . , , , , . [Sutter1].



2.6.2. Rvalue


C++11 . — rvalue-. Rvalue- C++ , , rvalue-. , , «» .


:


void Foo(T&& x);
void Foo(const T& x);

rvalue ( ), .


:


void Foo(T&& x);
void Foo(T x);

lvalue , rvalue , .


:


void Foo(T&& x);
void Foo(T& x);

rvalue , lvalue , .


, — rvalue, — , , . ( .) , , , .


++11, rvalue- — -. (lvalue/rvalue) this.


class X
{
public:
    X();
    void Foo() &;  // this   lvalue
    void Foo() &&; // this   rvalue
// ...
}; 
// ...
X x;
x.Foo ();  // Foo() &
X().Foo(); // Foo() &&

: rvalue- lvalue. , rvalue-, lvalue , - , std::move(), rvalue- .



2.6.3.




template<typename T>
void Foo(T&& x);

rvalue-, (universal reference). . lvalue x T&, const T&, rvalue T&&. x lvalue, - std::forward<T>(), , T&&, rvalue. (greedy), . , 2.5. (perfect forwarding) . [Meyers2].



3. ,



3.1.


C++ , - (, , , ), . (incomplete declaration), (forward declaration). . .


class X; //   X
class Y; //   Y
void Foo(X* x);
void Foo(Y* y);
// ...
X* px;
// ...
Foo(px); // void Foo(X* x);

X , .



3.2.


.


void Foo(int x);
void Foo(const char* x);
// ...
void (*pF)(int) = Foo; // Foo(int)

, . (, ) , ADL .


namespace N
{
    class X {/* ... */};
    void Foo(const X& x);
}
// ...
void (*pF)(const N::X&) = Foo;    // 
void (*pF)(const N::X&) = N::Foo; // OK
using N::Foo;
void (*pF)(const N::X&) = Foo;    // OK

.


void Foo(int x);
void Foo(const char* x);
// ...
auto pf = static_cast<void(*)(int)>(Foo); // Foo(int)

ADL .


, auto.


auto pf = Foo;

Foo , , pf Foo. Foo, , .


, (). std::function<>, , , std::sort(). .


- - .


class X
{
// ...
    void Foo(int a);
    void Foo(const char* a);
};
// ...
void (X::*pF)(int) = &X::Foo; // X::Foo(int)


3.3.


.



void Foo(int x);
void Foo() { Foo(0); }



void Foo(int x = 0);

, Foo(), . , .


void (*pF1)(int) = Foo; // OK
void (*pF0)() = Foo;    // , Foo    

.


, , .



3.4.


. , , , , , . («» , . 1.3). [Dewhurst]. — . , ( , - ), , . . , Visitor.



3.5.


, , — , . , . , .


, . -, std::input_iterator_tag. (typedef) — iterator_category. , -, iterator_category, , . :


void DisplayIterCat(std::input_iterator_tag tag)
{
    std::cout << "Input iterator\n";
}
//  DisplayIterCat   -
template<class Iter>
void DisplayIterCat(Iter it)
{
    DisplayIterCat(typename Iter::iterator_category());
}

typename. , iterator_category Iter.


C++ , , . :


template<typename T, T val>
struct integral_constant;

T T, , . :


typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

, , .


, . :


sizeof(Foo(expr))

. expr , . , Foo , Foo . .


C++17 if constexpr (), , . ( ) .



4.


— , . , .


, . , . , .


, .


— .





. Visitor


A, V


void DoDblDispatchOper(A* a, V* v);

a v , , a, v, . . , , . Visitor — [GoF].


, IAcceptor IVisitor.


class IVisitor;
class IAcceptor
{
public:
    virtual void Accept(IVisitor* visitor) = 0;
// ...
};
class A1;
class A2;
// ...
class IVisitor
{
public:
    virtual void Visit(A1* a) = 0;
    virtual void Visit(A2* a) = 0;
// ...
};
class A1 : public IAcceptor 
{
    void Accept(IVisitor* visitor) override
    {
        visitor->Visit(this);
    }
// ...
};
class A2 : public IAcceptor
{
    void Accept(IVisitor* visitor) override
    {
        visitor->Visit(this);
    }
// ...
};
// ...
class V1 : public IVisitor {/* ... */};
class V2 : public IVisitor {/* ... */};
// ...

IVisitor Visit() , IAcceptor. Visit() , .




void IAcceptor::Accept(IVisitor* visitor);

, :


visitor->Visit(this);

this , Visit(). Visit(), visitor.


void DoDblDispatchOper(IAcceptor* acceptor, IVisitor* visitor)
{
    acceptor->Accept(visitor);
}

Voila. .



.


- . — ( ) .


template<typename T>
void swap(T& a, T& b);

, , . . , std::swap() , , . , std::swap(), , , . , .


1. - Swap() ( ), .


class X
{
public:
    void Swap(X& other) noexcept;
// ...
};

, , C++11 noexcept.


2. , X ( , ), (-) swap() ( ):


inline void swap(X& a, X& b) noexcept { a.Swap(b); }

, ADL, std::swap() .


3. std::swap() X


namespace std
{
    template<>
    void swap<X>(X& a, X& b) noexcept { a.Swap(b); }
};

std , - . std.


, ? — . , , .


namespace N
{
    template<typename T>
// ...
    T x, y;
// ...
    swap(x, y);
// ...

, T swap(), , . std::swap() , , .



:


std::swap(x, y);

swap() std::swap() — . .


:


using std::swap;
swap(x, y);

, . std::swap(), . std::swap(). std::swap() .


, ( std)


std::swap(x, y);



swap(x, y);

[Meyers1] , .


, .


template<typename T>
class X
{
// ...
public:
    void Swap(X& other) noexcept;
};
template<typename T>
void swap(X<T>& a, X<T>& b) noexcept { a.Swap(b); }

std::swap() , std , , , , .


friend swap() :


template<typename T>
class X
{
// ...
    void Swap(X& other) noexcept;
    friend void swap(X& a, X& b) noexcept { a.Swap(b); }
};

, - Swap() .




[GoF]
., ., ., . - . .: . . — .: , 2001.
[Dewhurst]
, . C++. .: . . — .: , 2012.
[Meyers1]
, . C++. 55 .: . . — .: , 2014.
[Meyers2]
, . C++: 42 C++11 C ++14.: . . — .: «.. », 2016.
[Sutter1]
, . C++.: . . — : «.. », 2015.
[Sutter2]
Sutter, Lambang. Tugas kompleks baru di C ++.: Per. dari bahasa Inggris - M: LLC “Saya. Williams, 2015.



Source: https://habr.com/ru/post/undefined/


All Articles