系列文章目录
一、类型
1.auto用法
注意要点:编译器在编译阶段完成对auto的推导,就必须能让编译器推出其类型。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
using namespace std;
double foo()
{
return 1.1;
}
struct Test
{
int a;
};
void func(vector<int> &tmp)
{
for (auto i = tmp.begin(); i != tmp.end(); ++i)
{
}
}
int main(void)
{
auto b = 1;
auto c = foo();
Test str = { 0 };
auto d = str;
return 0;
}
________________________________________________________________________________________________________
auto易错点
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
using namespace std;
void func(auto a)
{
}
struct Test
{
int a;
auto b = 10;
};
int main(void)
{
auto a;
a = 10;
auto b[3] = { 1, 2, 3 };
vector<int> a;
vector<auto> b = { 1 };
system("pause");
return 0;
}
2.数据类型
定义数据类型
typedef int int32;
using my_int=int;
cout << is_same<int32, m_int>::value << endl;
decltype自动推导类型
float a;
double b;
decltype(a + b) c;
cout << typeid(c).name() << endl;
auto作为返回值和追踪返回类型
auto func2(int a, int b)
{
return a + b;
}
auto func3(int a, double b) -> decltype(a+b)
{
return a + b;
}
类中成员变量初始化
class A
{
public:
A(int i) : a(i)
{
}
int a;
};
class B
{
public:
int data{ 1 };
int data2 = 1;
A tmp{ 10 };
string name{ "mike" };
};
初始化列表
int a = 1;
char b = { 55};
int c{ 2 };
cout<<b<<endl;
int arr[] = { 1, 2, 3 };
int arr2[]{ 1, 2, 3 };
{}类型转化可以检测是否精度丢失
int a = 1024,c=1;
char b = a;
char b = { a };
char d=c;
char d={c};
基于范围的for循环
for (int &tmp : a)
{
tmp = 2 * tmp;
cout << tmp << ", ";
}
for (int tmp : a)
{
cout << tmp << ", ";
}
不能循环传参进来的数组里的值,因为传进来的是数组的地址。
void func(int a[])
{
for (int & tmp: a)
{
cout << tmp << endl;
}
}
静态断言
static_assert(sizeof(void *) == 4, "64位系统不支持");
枚举类型:枚举元素的作用域是全局的,所以其他枚举就不能使用其枚举元素名了
int main(void)
{
enum Status {Ok, Error=‘4’};
Status flag = Ok;
cout << sizeof(Ok)<<flag << endl;
return 0;
}
强枚举类型:枚举元素的作用域只在强枚举类型中,所以其他强枚举可以使用相同的枚举名。
int main()
{
enum class Status { Ok, Error };
enum struct Status2 { Ok, Error };
Status flag = Status::Ok;
enum struct Status3: char { Ok, Error };
cout << sizeof(Status3::Ok) << endl;
enum struct Status4: long long { Ok, Error };
cout << sizeof(Status4::Ok) << endl;
system("pause");
return 0;
}
常量表达式constexpr:修饰函数,变量,在编译阶段就得到结果,修饰函数时,函数里只能有typedef, using指令,静态断言和return;也就是说,被constexpr修饰的变量和函数里不能存在不能在编译阶段得到结果的变量。
constexpr int GetNum3()
{
static_assert(1, "fail");
return 3;
}
int main()
{
enum {e1=GetNum3(), e2};
constexpr int tmp = GetNum3();
enum {a1 = tmp, a2};
return 0;
}
原生字符串
cout << R"(hello, \n world)" << endl;
3.类
继承构造,在子类中using A::A,使用父类的构造函数,子类中不能在写自己的构造函数。
class A
{
public:
A(int x, int y)
{
a = x;
b = y;
}
protected:
int a;
int b;
};
class B:public A
{
public:
using A::A;
void display()
{
cout << "a = " << a << ", b = " << b << endl;
}
int tmp;
};
int main()
{
B obj(10, 20);
obj.display();
return 0;
}
委托构造
class Test
{
public:
Test():Test(1, 'a')
{
}
Test(int x): Test(x, 'b')
{
}
Test(char x): Test(11, x)
{
}
int a;
char b;
private:
Test(int x, char y): a(x), b(y)
{
}
};
final和override
virtual void func() final {}
virtual int func(int b) override{ }
C++ 的类有四类特殊成员函数,它们分别是:默认构造函数、析构函数、拷贝构造函数以 及拷贝赋值运算符。
C++11 标准引入了一个新特性:"=default"函数。程序员只需在函数声明后加上“=default;”, 就可将该函数声
明为 "=default"函数,编译器将为显式声明的 "=default"函数自动生成函数 体
class X
{
public:
X() =default;
X(int i)
{
a = i;
}
int a;
};
delete禁止函数使用 全局函数,类成员函数均可使用。
class X
{
public:
X() {}
X(const X &)=delete;
X & operator=(const X &)=delete;
X(int) =delete;
void *operator new(size_t) =delete;
void *operator new[](size_t) =delete;
};
模板的默认参数,类模板默认参数必须从由向左写。
template<class T, class T2=int>
class A{};
template<class T=int, class T2> void func2(T a, T2 b){}
template<class ... T>
void func(T... args)
{
cout << "num = " << sizeof...(args) << endl;}
int main()
{
func<int>(10);
func<int, int>(10, 20);
func<char, int>(10, 'a');
func<char, char *, int>('a', "abc", 250);
return 0;
}
/递归终止函数2
template<class T>
void debug(T tmp)
{
cout << "tmp = " << tmp << endl;
}
template<class T1, class ... T2>
void debug(T1 first, T2... last)
{
cout << first << endl;
debug(last...);
}
int main()
{
debug(1, 2, 3, 4);
return 0;
}
3.右值和移动函数
右值表示字面常量、表达式、函数的非引用返回值等,也就是不能取地址的值
左值引用不能引用常数,const修饰的数和const int&类型
int a;
const aa=1;
int &b = a;
int &s=a;
const int &d = a;
const int &e = 1;
const int &f = func();
const int tmp = 10;
const int &g = tmp;
int && a = 10;
int && b = func02();
int && c =a;
int i = 10;
int j = 20;
int && c = i+j;
int k = 10;
int && d = k;
int a = 10;
int && c = std::move(a);
转移构造函数和转移赋值函数,通过浅拷贝将临时对象被新的指针指向,这样函数返回值就不会被delete掉。
class MyString
{
public:
MyString(const char *tmp = "abc")
{
len = strlen(tmp);
str = new char[len+1];
strcpy(str, tmp);
cout << "普通构造函数 str = " << str << endl;
}
MyString(const MyString &tmp)
{
len = tmp.len;
str = new char[len + 1];
strcpy(str, tmp.str);
cout << "拷贝构造函数 tmp.str = " << tmp.str << endl;
}
MyString(MyString && t)
{
str = t.str;
len = t.len;
t.str = NULL;
cout << "移动构造函数" << endl;
}
MyString &operator= (const MyString &tmp)
{
if(&tmp == this)
{
return *this;
}
len = 0;
delete []str;
len = tmp.len;
str = new char[len + 1];
strcpy(str, tmp.str);
cout << "赋值运算符重载函数 tmp.str = " << tmp.str << endl;
return *this;
}
MyString &operator=(MyString &&tmp)
{
if(&tmp == this)
{
return *this;
}
len = 0;
delete []str;
len = tmp.len;
str = tmp.str;
tmp.str = NULL;
cout << "移动赋值函数\n";
return *this;
}
~MyString()
{
cout << "析构函数: ";
if(str != NULL)
{
cout << "已操作delete, str = " << str;
delete []str;
str = NULL;
len = 0;
}
cout << endl;
}
private:
char *str = NULL;
int len = 0;
};
forward保持传入参数的int& int&&和const int&属性
MyString func()
{
MyString obj("mike");
return obj;
}
int main()
{
MyString &&tmp1 = func();
MyString tmp("abc");
tmp = func();
return 0;
}
template<class T> void func(const T &)
{
cout << "const T &" << endl;
}
template<class T> void func(T &)
{
cout << "T &" << endl;
}
template<class T> void func(T &&)
{
cout << "T &&" << endl;
}
template<class T> void forward_val(T &&tmp)
{
func( std::forward<T>(tmp) );
}
int main()
{
int a = 0;
const int &b = 1;
forward_val(a);
forward_val(b);
forward_val(111);
return 0;
}
4.智能指针
unique指针
unique_ptr<int> up1(new int(11));
unique_ptr<int> up2 = std::move(up1);
cout << "*up2 = " << *up2 << endl;
unique_ptr<int> up1(new int(11));
int * p = up1.release();
cout << *p << endl;
delete p;
unique_ptr<Test> up2(new Test);
up2 = nullptr;
up2 = NULL;
up2.reset();
up2.reset();释放智能指针其实就是把堆区的指针数变成零,所以我们多次将指针指向null也不会报错,因为系统会当指针数为0的时候就释放内容了。
shared_ptr
shared_ptr<int> sp1(new int(11));
shared_ptr<int> sp2 = sp1;
cout << "num = " << sp2.use_count() << endl;
sp1.reset();
cout << "num = " << sp2.use_count() << endl;
cout << *sp2 << endl;
sp2.reset();
cout << "num = " << sp2.use_count() << endl;
weak_ptr:
weak_ptr<int> wp = p1;
wp.use_count();
wp.lock();
int main()
{
shared_ptr<int> p1(new int(11));
shared_ptr<int> p2 = p1;
weak_ptr<int> wp = p1;
cout << "num = " << p1.use_count() << endl;
cout << "num = " << wp.use_count() << endl;
shared_ptr<int> p3 = wp.lock();
cout << "num2 = " << p1.use_count() << endl;
cout << "num2 = " << wp.use_count() << endl;
cout << *p1 << ", " << *p2 << ", " << *p3 << endl;
p1.reset();
p2.reset();
p3.reset();
cout << "num3 = " << p1.use_count() << endl;
cout << "num3 = " << wp.use_count() << endl;
shared_ptr<int> tmp = wp.lock();
if(tmp == nullptr)
{
cout << "堆区空间已经释放\n";
}
return 0;
}
5.函数绑定
#include <iostream>
#include <functional>
using namespace std;
void func()
{
cout << __func__ << endl;
}
class Test
{
public:
static int test_func(int a)
{
cout << __func__ << "(" << a << ") ->: ";
return a;
}
};
class MyFunctor
{
public:
int operator()(int a)
{
cout << __func__ << "(" << a << ") ->: ";
return a;
}
};
int main()
{
function<void(void)> f1 = func;
f1();
function<int(int)> f2 = Test::test_func;
cout << f2(10) << endl;
MyFunctor obj;
function<int(int)> f3 = obj;
cout << f3(22) << endl;
return 0;
}
void func(int x, int y)
{
cout << x << " " << y << endl;
}
int main()
{
bind(func, 11, 22)();
bind(func, std::placeholders::_1, std::placeholders::_2)(11, 22);
using namespace std::placeholders;
bind(func, 11, _1)(22, 33, 44);
bind(func, _2, _1)(11, 22);
bind(func, _2, 22)(11, 0);
bind(func, _3, 22)(11, 1, 3);
return 0;
}
class Test
{
public:
void func(int x, int y)
{
cout << x << " " << y << endl;
}
int a;
};
int main()
{
Test obj;
function<void(int, int)> f1 = bind(&Test::func, &obj, _1, _2);
f1(11, 22);
function<int &()> f2 = bind(&Test::a, &obj);
f2() = 111;
cout << "obj.a = " << obj.a << endl;
return 0;
}
6.lambda
空。没有使用任何函数对象参数。
=。函数体内可以使用 lambda 所在作用范围内所有可见的局部变量(包括 lambda 所在类的 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局 部变量)。
? &。函数体内可以使用 lambda 所在作用范围内所有可见的局部变量(包括 lambda 所在类的 this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所 有局部变量)。
? this。函数体内可以使用 lambda 所在类中的成员变量。
? a。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝, 因为默认情况下函数是 const 的。要修改传递进来的 a 的拷贝,可以添加 mutable 修饰符。
? &a。将 a 按引用进行传递。
? a, &b。将 a 按值进行传递,b 按引用进行传递。
? =,&a, &b。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
? &, a, b。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。
int tmp = 1;
class Test
{
public:
int i = 0;
void func()
{
int a = 10;
auto f1 = [=]()
{
cout << i << endl;
cout << tmp << endl;
};
auto f2 = [&](){ cout << i << endl; };
auto f3 = [this]()
{
cout << i << endl;
cout << tmp << endl;
};
}
};
int main()
{
int a = 0;
int b = 0;
int c = 0;
auto f1 = [](){ };
auto f2 = [a, b](){ cout << a << ", " << b << endl; };
auto f3 = [a, b](int x, int y)
{
cout << a << ", " << b << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
};
auto f4 = [=]{cout << a << ", " << b << endl;};
auto f5 = [&]{cout << a << ", " << b << endl;};
auto f6 = [&, a]{cout << a << ", " << b << endl;};
auto f7 = [=, &a]{cout << a << ", " << b << endl;};
auto f8 = [=]() mutable
{
a++;
cout << tmp << endl;
};
return 0;
}
class MyFunctor
{
public:
MyFunctor(int i): r(i) {}
int operator() (int tmp)
{
return tmp+r;
}
private:
int r;
};
int main()
{
int tmp = 10;
MyFunctor obj(tmp);
cout << "result1 = " << obj(1) << endl;
auto f = [&](int t)
{
return tmp+t;
};
cout << "result2 = " << f(1) << endl;
return 0;
}
function<int(int)> f1 = [](int a) { return a; };
function<int()> f2 = bind([](int a){ return a; }, 123);
lambda优势
for_each(largeNums.begin(), largeNums.end(),
[](int &n)
{
cout << n << ", ";
}
);
cout << endl;
7.类型转换
char a = 'a';
int b = static_cast<char>(a);
double *c = new double;
void *d = static_cast<void*>(c);
int e = 10;
const int f = static_cast<const int>(e);
const int g = 20;
int *h = static_cast<int*>(&g);
if(Derived *dp = static_cast<Base *>(bp)){
}
else{
}
if(Base*bp = static_cast<Derived *>(dp)){
}
else{
}
const_cast将常量指针常量引用转换成非常量指针引用:在通过非常量指针修改内存值。
①常量指针被转化成非常量的指针,并且仍然指向原来的对象;
②常量引用被转换成非常量的引用,并且仍然指向原来的对象;
③const_cast一般用于修改底指针。如const char *p形式。
const int g = 20;
int *h = const_cast<int*>(&g);
*h=40;
const int g = 20;
int &h = const_cast<int &>(g);
const char *g = "hello";
char *h = const_cast<char *>(g);
dynamic_cast
Derived *dp = dynamic_cast<Base *>(bp)
父类指针强转成子类且父类存在虚函数时,建议使用dynamic,可以检测是否存在越界的风险
reinterpret_cast强转
int n=1;
int *p=(int*)n;
int *p=reinterpret_cast<int*>(n);
Derived *dp=reinterpret_cast<Base*>(bp);
8.字符串和数值转换
string pi = "pi is " + to_string(3.1415926);
int intpi = stoi(pi);
|