🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁
🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言
📍内容导读📍
C++ 11
namespace经验之谈
-
在编写库或框架时,可以使用命名空间来避免与用户代码的命名冲突。通过将库的所有内容放在一个命名空间中,可以确保库的名称不会与用户代码中的其他名称冲突。
-
避免在头文件中使用using namespace语句。在头文件中使用using namespace语句会将整个命名空间的内容引入到全局作用域中,可能导致命名冲突和代码的不可预测性。最好的做法是在源文件中使用using语句,或者使用命名空间限定符来访问命名空间中的内容。
-
命名空间可以嵌套使用,以创建更复杂的命名空间结构。嵌套的命名空间可以更好地组织代码,并提供更好的可读性。
-
当使用第三方库时,可以将其放在一个自定义的命名空间中,以避免与自己的代码或其他第三方库的命名冲突。
转换函数
1. 转换函数没有返回类型,但在函数声明前加上了要转换的目标类型。
2. 转换函数必须是类的成员函数,不能是静态函数。
3. 转换函数没有参数。
4. 转换函数可以被隐式调用,也可以被显式调用。
class Fraction
{
public:
Fraction(int num,int den=1)
: m_numerator(num), m_denominator(den) { }
-----------------------------------------转换函数
operator double() const { // const
return (double) (m_numerator / m_denominator);
}
-----------------------------------------
private:
int m_numerator; //分子
int m_denominator; //分母
};
智能指针
Pointer-like classes是指那些行为类似指针的自定义类。这些类在使用上具有类似指针的语义,可以进行解引用、指针算术运算等操作。
解引用操作符(*):重载解引用操作符,使得对象可以被解引用。例如,
T& operator*() const
。成员访问操作符(->):重载成员访问操作符,使得对象可以像指针一样使用箭头操作符。例如,
T* operator->() const
。指针算术运算符:重载指针算术运算符,使得对象可以进行指针的加减操作。例如,
T* operator+(int n) const
。比较运算符:重载比较运算符,使得对象可以进行指针的比较操作。例如,
bool operator==(const self& other) const
。
template<class T>
class shared_ptr
{
public:
T& operator*() const
{ return *px; }
T* operator->() const
{ return px; }
shared_ptr(T* p) : px(p) { }
private:
T* px;
long* pn;
....
};
迭代器
迭代器是一种指向容器中元素的对象,类似于指针的行为。迭代器允许我们遍历容器中的元素,并对其进行访问和操作。因此,迭代器可以被认为是一种指向容器元素的指针。
template<class T, class Ref, class Ptr>
struct _list_iterator{
typedef _list_iterator<T, Ref, Ptr> self;typedef Ptr pointer; typedef Ref reference;
...
bool operator ==(const self& x) const { return node == x.node;}
bool operator !=(const self& x) const { return node != x.node;}
reference operator*() const { return (*node),date; }
pointer operator->() const { return &(operator*()); }
self& operator++() { ...}
self& operator++(int) {...}
解引用操作符(*):重载解引用操作符,使得迭代器可以被解引用,获取当前指向的元素。例如,
T& operator*() const
。成员访问操作符(->):重载成员访问操作符,使得迭代器可以像指针一样使用箭头操作符,访问当前指向的元素的成员。例如,
T* operator->() const
。前置递增运算符(++):重载前置递增运算符,使得迭代器可以向前移动到下一个元素。例如,
MyIterator& operator++()
。后置递增运算符(++):重载后置递增运算符,使得迭代器可以向前移动到下一个元素,并返回移动前的迭代器。例如,
MyIterator operator++(int)
。比较运算符:重载比较运算符,使得迭代器可以进行指针的比较操作。例如,
bool operator==(const MyIterator& other) const
。
仿函数
仿函数(Function-like classes)是一种重载了函数调用运算符(operator())的类,使其可以像函数一样被调用。这种类的对象可以像函数一样接受参数并返回结果。
#include <iostream>
class Adder {
public:
int operator()(int a, int b) {
return a + b;
}
};
int main() {
Adder add;
int result = add(3, 4);
std::cout << "Result: " << result << std::endl;
return 0;
}
有一些奇特的基类(base classes)用于定义和实现仿函数(Function Object)如下所例:std::unary_function和std::binary_function: 这两个基类是过时的,自C++11起已被弃用。它们用于定义一元和二元仿函数的参数类型和返回类型。在C++11之后,可以直接使用函数调用运算符(operator())的参数和返回类型来定义仿函数。
auto
auto是一个关键字,用于声明变量的类型自动推导。通过使用auto关键字,编译器可以根据变量的初始化值自动推断出变量的类型,从而简化代码并提高可读
list<string>c;
...
auto ite = find(c.begin(), c.end(), target);//赋值的时候,auto 会自动推出类型
//声明变量的时候不能使用auto, 推不出来类型
range-base for loop
range-based for循环是一种用于遍历容器或其他可迭代对象的循环结构。它提供了一种更简洁和直观的方式来遍历元素,而不需要使用索引或迭代器。
for (element : container) { // 循环体 }
for (int i : {2, 3, 5, 7, 9, 13, 17, 19}){
cout<< i << endl;
}
vector<double> vec;
...
for ( auto elem : vec ) {//pass by value
cout <<elem <<endl;
}
for ( auto& elem : vec ) {//pass by reference
elem *= 3;
}
lambda
C++模板
类模板
类模板是一种用于定义通用类的机制。通过类模板,可以定义一个通用的类模板,并使用类型参数来表示类中的数据类型或成员函数的参数类型。
template<typename T>
class complex
{
public:
complex( T r = 0,T i = 0): re (r), im (i){ }
comp1ex& operator+=(const complex&);
T real () const { return re; }
T imag () const { return im; }
private:
T re,im ;
friend complex& _doapl (complex* , const complex&);
};
{
complex<double>c1(2.5,1.5);//使用方法
complex<int> c2(2,6);
...
}
函数模板
函数模板是一种用于定义通用函数的机制。通过函数模板,可以定义一个通用的函数模板,并使用类型参数来表示函数中的参数类型。这样,可以在不同的上下文中使用相同的函数模板,只需提供不同的类型参数。
class stone
{
public:
stone(int w,int h, int we): _w ( w ),_h (h), _weight (we){}
bool operator<(const stone& rhs) const { return _weight < rhs._weight; }
private:
int _w, _h,_weight;
};
template <class T>
inline
const T& min (const T&a, const r& b)
{
return b < a ? b : a ;
}
成员模板
成员模板是一种在类中定义的模板函数或模板成员函数。它允许在类中使用通用的函数模板,并将其作为类的成员函数。
template <class T1,class T2>
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair ()
: first(T1()) , second(T2()) { }
pair (const T1& a, const T2& b)
: first(a) , second(b) { }
template <class U1, class U2>
pair (const pair<U1, U2>& p)
: first(p.first) , second(p.second) { } //把初值的头尾放进来,放入本身的头尾
//把子类赋给对应的父类,up-cast
};
成员模板可以在类的内部定义,也可以在类的外部定义。如果成员模板在类的内部定义,它将自动成为类的成员函数。如果成员模板在类的外部定义,需要使用类的作用域解析运算符(::)来指定它是类的成员函数。
成员模板可以使用类的类型参数,也可以使用成员函数的类型参数。
成员模板可以访问类的私有成员。
成员模板可以被特化。
成员模板可以被重载。
模板特化
模板特化是指为特定的类型提供特定的模板实现。当需要针对某些特定类型的参数,提供不同的实现时,可以使用模板特化。
完全特化:完全特化是指为特定的类型参数提供完全不同的实现。完全特化的语法是在模板名称后面加上尖括号,并在尖括号内指定特定的类型参数。
template <class Key>//泛化
struct hash { };
//特化
template<>
struct hash<char> {
size_t operator () (char x) const { return x; }
};
template<>
struct hash<char> {
size_t operator () (int x) const { return x; }
};
template<>
struct hash<char> {
size_t operator () (long x) const { return x; }
};
偏特化:是模板特化的一种特殊形式,一般来说,所谓的特化是指将所有的模板参数进行替换成具体类型,而偏特化是指将部分参数类型指定为具体类型。
范围的偏 | 个数的偏 |
![]() | ![]() |
模板模板参数
模板模板参数(Template Template Parameter)是C++中的一种模板技术,允许在定义模板时使用另一个模板作为其参数。
例如,假设有一个模板类template<typename T, template<typename> class Container>
,其中Container
是一个模板模板参数,它接受一个类型参数,并用于定义一个容器类。这样,我们可以在使用这个模板类时,通过不同的容器模板作为Container
来实例化不同类型的容器。
variadic templates(数量不定的模板参数)
C++中的一种特性,允许函数和类接受任意数量的不同类型的参数。...就是一个所谓的pack(包)属于语法
C++对象模型
复合&继承关系下的构造和析构
C++面向对象高级编程(上)_LS_o.0的博客-CSDN博客
vptr
虚指针和 vtbl
虚表再现
动态绑定必须满足三个条件,(而静态绑定一定调用到某个地址。),实现 多态:
- 必须是用指针来调用,如上面的
p
指针; - 这个指针是向上转型的(祖先);
- 调用的是虚函数。
this
指针,动态绑定
关于Dynamic Binding
现在考虑一下,为什么动态绑定解析成C语言形式会是:
(*(p->vptr)[n])(p) //第二个p其实就是this指针(因为p是调用者)
//或
(* p->vptr[n])(p)
下图中 a是一个对象,它调用函数是一个静态绑定,可以看到汇编呈现的就是:Call xxx一个地址
下图中pa满足动态绑定的三个条件,所以它是一个动态绑定,而在汇编语言中,汇编所呈现出来的那部分命令就等价于C语言中的(*(p->vptr)[n])(p)
重载new([ ])/delete([ ])
重载new
和delete
运算符来自定义内存的分配和释放行为。通过重载这两个运算符,我们可以使用自定义的内存管理策略,例如从特定的内存池中分配内存,或者进行内存跟踪和调试。
重载new
运算符的一般语法形式如下: size
参数表示要分配的内存大小,函数的返回类型是void*
,表示分配的内存地址。
void* operator new(size_t size) {
// 自定义的内存分配逻辑
// 返回分配的内存地址
}
void* operator new[](size_t size) {
// 自定义的内存分配逻辑
// 返回分配的内存地址
}
重载delete
运算符的一般语法形式如下: ptr
参数表示要释放的内存地址。
void operator delete(void* ptr) {
// 自定义的内存释放逻辑
}
void operator delete[](void* ptr) {
// 自定义的内存释放逻辑
}
重载 member operator new([ ])/delete([ ])
重载类的成员new
运算符的一般语法形式如下:
void* ClassName::operator new(size_t size) {
// 自定义的内存分配逻辑
// 返回分配的内存地址
}
重载类的成员delete
运算符的一般语法形式如下:
void ClassName::operator delete(void* ptr) {
// 自定义的内存释放逻辑
}
placement new / delete
参数列表的第一个参数必须为size_t,其余参数以new所指定的placement arguments为初值。出现在new(......)小括号内的便是所谓的placement arguments。
只有当new所调用的构造函数(new被分解的第一步)抛出异常,才会调用与new对应的那个重载operator delete(),主要用来归还未能完全创建成功的对象所占用的内存。
placement new的应用:Basic_String使用new(extra)扩充申请量
std::basic_string是C++标准库中的字符串类模板,它在内部使用动态分配的内存来存储字符串数据。当字符串的长度超过当前内存容量时,std::basic_string会重新分配更大的内存,并将原有的数据复制到新的内存位置。为了避免频繁的内存分配和复制操作,std::basic_string使用了placement new来在预先分配的内存块中构造新的字符串对象。这个预先分配的内存块通常称为"extra"空间。