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
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(42);
Foo("meow");
}
, Foo
, using
- :
namespace N
{
void Foo(int x);
}
void Foo(const char* x);
using N::Foo;
void Test()
{
Foo(42);
Foo("meow");
}
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);
Foo("meow");
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(x = y);
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(42);
, , int
long
.
void Foo(int x);
void Foo(long x);
Foo(42);
Foo(42L);
. . , , . :
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(nullptr);
C++98
Foo((void*)0);
. nullptr
, nullptr
.
void Foo(void* x);
void Foo(std::nullptr_t);
void* x = nullptr;
Foo(x);
Foo(nullptr);
.
2.3.
++11 (uniform initialization) — std::intializer_list<>
. , , . . .
- —
{}
, . , . - ,
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);
template<>
void Foo<double>(double x);
template<>
void Foo<const char*>(const char* x);
template<typename T>
void Foo(const T* x);
template<typename T>
class U {};
template<typename T>
void Foo(U<T> u);
, :
Foo(42);
Foo(3.14);
Foo(42L);
Foo("meow");
Foo(U<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);
template<typename T>
void Foo(T x)
{
if constexpr (std::is_integral<T>::value)
{
FooInt(x);
}
else
{
FooEx(x);
}
}
template<typename T>
void Foo(T x)
{
std::is_integral<T>::value
? FooInt(x)
: FooEx(x);
}
<type_traits>
.
2.6. «»
«» : , , , rvalue .
. :
- lvalue — ;
- () lvalue — ;
- rvalue — lvalue,
std::move();
- () 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();
void Foo() const;
void DoSomething() const;
void DoSomethingElse();
};
void X::DoSomething() const
{
Foo();
}
void X::DoSomethingElse()
{
Foo();
}
X x;
x.Foo();
const X cx;
cx.Foo();
H - rvalue , rvalue. rvalue .
class X
{
public:
X();
void Swap(X& other) noexcept;
};
X x;
X().Swap(x);
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() &;
void Foo() &&;
};
X x;
x.Foo ();
X().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;
class Y;
void Foo(X* x);
void Foo(Y* y);
X* px;
Foo(px);
X
, .
3.2.
.
void Foo(int x);
void Foo(const char* x);
void (*pF)(int) = Foo;
, . (, ) , ADL .
namespace N
{
class X {};
void Foo(const X& x);
}
void (*pF)(const N::X&) = Foo;
void (*pF)(const N::X&) = N::Foo;
using N::Foo;
void (*pF)(const N::X&) = Foo;
.
void Foo(int x);
void Foo(const char* x);
auto pf = static_cast<void(*)(int)>(Foo);
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;
3.3.
.
void Foo(int x);
void Foo() { Foo(0); }
void Foo(int x = 0);
, Foo()
, . , .
void (*pF1)(int) = Foo;
void (*pF0)() = 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";
}
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.