C ++ es un lenguaje complejo e interesante, puede mejorarlo casi toda su vida. En algĂşn momento, querĂa estudiarlo de la siguiente manera: tomar algĂşn aspecto del lenguaje, posiblemente bastante limitado, y tratarlo de la manera más profunda y detallada posible. Este enfoque fue ampliamente estimulado por los notables libros de Scott Meyers, Herb Sutter y Stephen Dewhurst. Cuando se acumulĂł una cierta cantidad de materiales, decidĂ presentarles Khabrovchan. AsĂ que estaba esta serie, que llamĂ© "C ++, cavando en profundidad". La serie está marcada como Tutorial, pero todavĂa se centra no en principiantes, sino en el nivel intermedio. El primer tema es la sobrecarga en C ++. El tema resultĂł ser muy extenso y obtuvimos tres artĂculos. El primer artĂculo trata sobre la sobrecarga de funciones y plantillas, el segundo sobrecarga de operadores y el tercero sobrecarga de operadoresnew/delete
. Entonces, comencemos a cavar.
Tabla de contenido
IntroducciĂłn
En un sentido amplio, la sobrecarga es la capacidad de usar simultáneamente varias funciones con el mismo nombre. El compilador los distingue por el hecho de que tienen un conjunto diferente de parámetros. En los puntos de llamada, el compilador analiza los tipos de argumentos y determina qué función particular debe llamarse. En la literatura en ruso, a veces se puede encontrar el término "compartir", pero no parece haber arraigado.
La sobrecarga es compatible con muchos lenguajes de programaciĂłn, consideraremos solo C ++ 17.
1. Disposiciones generales
1.1. Funciones sobrecargadas
( ) (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, escudo de armas. Nuevas tareas complejas en C ++.: Per. De inglés - M: LLC "I.D. Williams, 2015.