لغة C ++ هي لغة معقدة ومثيرة للاهتمام ، يمكنك تحسينها طوال حياتك تقريبًا. في مرحلة ما ، كنت أرغب في دراستها على النحو التالي: خذ بعض جوانب اللغة ، ربما ضيقة للغاية ، والتعامل معها بعمق وتفصيل ممكن. تم تحفيز هذا النهج إلى حد كبير من خلال الكتب الرائعة لسكوت مايرز ، هيرب سوتر ، وستيفن ديهورست. عندما تراكمت كمية معينة من المواد ، قررت تقديم خبروفشان لهم. لذلك كانت هناك هذه السلسلة ، التي أسميتها "C ++ ، والحفر بعمق". تم وضع علامة على المسلسل على أنه برنامج تعليمي ، لكنه لا يزال يركز ليس على المبتدئين ، بل على المستوى المتوسط. الموضوع الأول هو التحميل الزائد في C ++. اتضح أن الموضوع كان واسع النطاق ولدينا ثلاث مقالات. تدور المقالة الأولى حول وظائف القوالب الزائدة ، والثانية هي عوامل التحميل الزائد والثالثة هي عوامل التحميل الزائدnew/delete
. لذا ، فلنبدأ الحفر.
جدول المحتويات
المقدمة
بمعنى واسع ، التحميل الزائد هو القدرة على استخدام العديد من الوظائف في نفس الوقت بنفس الاسم. يميزها المترجم لأن لديهم مجموعة مختلفة من المعلمات. في نقاط الاتصال ، يحلل المترجم أنواع الحجج ويحدد الوظيفة المحددة التي يجب استدعاؤها. في الأدب باللغة الروسية ، يمكن العثور على مصطلح "المشاركة" في بعض الأحيان ، ولكن لا يبدو أنه قد تأصل.
التحميل الزائد مدعوم بالعديد من لغات البرمجة ، سننظر فقط في C ++ 17.
1. أحكام عامة
1.1. وظائف فوق طاقتها
( ) (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]
سوتر ، شعار النبالة . المهام المعقدة الجديدة في C ++.: Per. من الانجليزية - م: LLC “I.D. ويليامز ، 2015.