1 const
2 const_cast
3 decltype
4 default
5 delete
6 dynamic_cast
7 explicit
8 mutable
9 reinterpret_cast
10 static_cast
11 typeid
1 const
类的数据如果是const属性,需要初始化,否则报错
error C2789: “fush::d”: 必须初始化常量限定类型的对象
1 struct fushu 2 { 3 const int d;//error C2789: “fush::d”: 必须初始化常量限定类型的对象 4 };
类的函数如是是const属性,则内部不能修改数据,否则报错
error C3490: 由于正在通过常量对象访问“a”,因此无法对其进行修改
1 struct fushu 2 { 3 int a; 4 mutable int b; 5 void showabc() const 6 { 7 this->a = 10;//error C3490: 由于正在通过常量对象访问“a”,因此无法对其进行修改 8 this->b = 10; 9 } 10 };
2 const_cast
const_cast用于去掉常量const属性
dynamic_cast用于类的多态之间的指针转换,只能用于含有虚函数的类。将多态类型向下转型dowcast为其实际类型。
reinterpret_cast用于指针的转换。
static_cast用于常规的数据类型转换。只有当类型转换有所定义,整个转换才会成功。
const_cast,用于修改类型的const或volatile属性。
const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
一、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
二、常量引用被转换成非常量的引用,并且仍然指向原来的对象;
三、const_cast一般用于修改底指针。如const char *p形式。
1 #include <iostream> 2 using namespace std; 3 4 void main() 5 { 6 const int num = 5; 7 8 int *p = const_cast<int *>(&num);//强制去掉const属性 9 10 *p = 4; 11 12 std::cout << num << std::endl;//仍然是5,无法通过指针修改 13 14 system("pause"); 15 }
//const int num=10;可以修改,但是无法生效,编译的时候不读内存
//const int *p指向变量限定权限,只读不可写
//const_cast去掉常量属性
//error C3892: “p”: 不能给常量赋值
1 #include <iostream> 2 using namespace std; 3 4 //const int num=10;可以修改,但是无法生效,编译的时候不读内存 5 //const int *p指向变量限定权限,只读不可写 6 //const_cast去掉常量属性 7 8 void main() 9 { 10 int num[3] = { 1,2,3 }; 11 12 const int *p = num; 13 14 //*p = 10;//error C3892: “p”: 不能给常量赋值 15 16 int *pnew = const_cast<int *>(p); 17 18 *pnew = 10; 19 20 system("pause"); 21 }
3 decltype
根据一个变量,创建一个备份
1 #include <iostream> 2 using namespace std; 3 4 void main() 5 { 6 double db(10.9); 7 8 decltype(db) newdb(10.9);//通用备份接口,类似Java反射 9 10 std::cout << sizeof(newdb) << " " << newdb << std::endl; 11 12 system("pause"); 13 }
//自动数据类型,根据实际推导出类型
1 #include <iostream> 2 using namespace std; 3 4 //自动数据类型,根据实际推导出类型 5 6 template <class T1, class T2>//根据参数类型获取类型 7 auto get(T1 data, T2 bigdata)->decltype(data*bigdata) 8 { 9 return data*bigdata; 10 } 11 12 void main() 13 { 14 std::cout << typeid(get(12.0, 'A')).name() << std::endl;//double 15 16 std::cout << get(12.0, 'A') << std::endl;//780 17 18 std::cout << typeid(get(12, 'A')).name() << std::endl;//int 19 20 std::cout << get(12.0, 'A') << std::endl;//780 21 22 system("pause"); 23 }
4 default
default和delete搭配使用,用于函数
5 delete
//delete可以禁用默认生成的函数
//禁用构造可以无法实例化
//禁用拷贝构造函数,可以实现禁止别人复制
//default默认存在
//error C2280: “myclassA::myclassA(const myclassA &)”: 尝试引用已删除的函数
1 #include <iostream> 2 3 //delete可以禁用默认生成的函数 4 //禁用构造可以无法实例化 5 //禁用拷贝构造函数,可以实现禁止别人复制 6 //default默认存在 7 class myclassA 8 { 9 public: 10 myclassA() = default;//default默认存在 11 myclassA(const myclassA &) = delete;//拷贝构造函数,delete禁用 12 }; 13 14 void main() 15 { 16 myclassA myclassa1; 17 18 myclassA myclassa2(myclassa1);//error C2280: “myclassA::myclassA(const myclassA &)”: 尝试引用已删除的函数 19 20 myclassA myclassa3 = myclassa1;//error C2280: “myclassA::myclassA(const myclassA &)”: 尝试引用已删除的函数 21 22 system("pause"); 23 }
6 dynamic_cast
const_cast用于去掉常量const属性
dynamic_cast用于类的多态之间的指针转换,只能用于含有虚函数的类。将多态类型向下转型dowcast为其实际类型。
reinterpret_cast用于指针的转换
static_cast用于常规的数据类型转换。只有当类型转换有所定义,整个转换才会成功。
将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理
dynamic_cast <type-id> (expression)
该运算符把expression转换成type-id类型的对象。Type-id 必须是类的指针、类的引用或者void*;
如果 type-id 是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。
面试,虚函数有虚函数表,可以确定数据类型
dynamic_cast必须要有虚函数,根据虚函数表进行转换,否则转换失败
dynamic_cast转换成功是地址,转换失败为空
类的空指针可以调用不调用数据成员的成员函数
1 #include <iostream> 2 3 //面试,虚函数有虚函数表,可以确定数据类型 4 //dynamic_cast必须要有虚函数,根据虚函数表进行转换,否则转换失败 5 //dynamic_cast转换成功是地址,转换失败为空 6 //类的空指针可以调用不调用数据成员的成员函数 7 8 class A 9 { 10 public: 11 int num; 12 static int data; 13 virtual void run()//虚函数 14 { 15 std::cout << "Arun" << std::endl; 16 } 17 }; 18 19 class B :public A 20 { 21 public: 22 int num; 23 static int data; 24 virtual void run()//虚函数 25 { 26 std::cout << "Brun" << std::endl; 27 } 28 void test() 29 { 30 std::cout << "Btest" << std::endl; 31 } 32 }; 33 34 int A::data = 1; 35 int B::data = 2; 36 37 void main() 38 { 39 A a1; 40 B b1; 41 42 A *p1 = &a1;//直接用基类指针引用基类对象 43 A *p2 = &b1;//用基类指针引用一个派生类对象 44 B *p3(nullptr);//派生类指针,为空 45 46 p3 = dynamic_cast<B *>(p1); 47 48 p3->test(); 49 50 system("pause"); 51 }
7 explicit
C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。
//error C2440 : “初始化” : 无法从“int”转换为“classobj”
//note : class“classobj”的构造函数声明为“explicit”
1 #include <iostream> 2 3 class classobj 4 { 5 public: 6 int num; 7 public: 8 explicit classobj(int data) 9 { 10 this->num = data; 11 std::cout << "被构造" << std::endl; 12 } 13 ~classobj() 14 { 15 16 } 17 }; 18 19 void main() 20 { 21 //classobj num = 5;//让人误会以为是类型转换 22 23 //error C2440 : “初始化” : 无法从“int”转换为“classobj” 24 //note : class“classobj”的构造函数声明为“explicit” 25 26 classobj data(5); 27 28 system("pause"); 29 }
8 mutable
mutable 可以用来指出,即使成员函数或者类变量为const,其某个成员也可以被修改。
在c++的类中, 如果一个成员函数被const 修饰,那么它将无法修改其成员变量的,但是如果这个成员变量是被mutable修饰的话,则可以修改。
e有mutable,即使成员函数为const,e仍然可以被修改
1 mutable int e = 9; 2 3 void showabc() const 4 { 5 this->e = 10; 6 std::cout << this->a << this->b << this->c << std::endl; 7 }
9 reinterpret_cast
const_cast用于去掉常量const属性
dynamic_cast用于类的多态之间的指针转换,只能用于含有虚函数的类。将多态类型向下转型dowcast为其实际类型。
reinterpret_cast用于指针的转换
static_cast用于常规的数据类型转换。只有当类型转换有所定义,整个转换才会成功。
reinterpret_cast是C++里的强制类型转换符。
reinterpret_cast<type-id> (expression) type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
//指针,强类型,类型决定了数据的解析方式,内存占多大
1 #include <iostream> 2 using namespace std; 3 4 //指针,强类型,类型决定了数据的解析方式,内存占多大 5 6 void main() 7 { 8 int num(3); 9 10 char *p = reinterpret_cast<char *>(&num); 11 12 for (int i = 0; i < 4; i++) 13 { 14 printf("%c,%d,%p\n", *(p + i), *(p + i), p + i); 15 } 16 17 system("pause"); 18 }
10 static_cast
const_cast用于去掉常量const属性
dynamic_cast用于类的多态之间的指针转换,只能用于含有虚函数的类。将多态类型向下转型dowcast为其实际类型。
reinterpret_cast用于指针的转换
static_cast用于常规的数据类型转换。只有当类型转换有所定义,整个转换才会成功。
float x = 10.1f; std::cout << static_cast<int>(x) << std::endl;//由float转换到int有所定义 f(static_cast<std::string>("hello world!"));//由char *转换到string有所定义
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
static_cast < type-id > ( expression )
1 #include <iostream> 2 using namespace std; 3 4 void main() 5 { 6 int n = static_cast<int>(78.98); 7 8 std::cout << n << std::endl;//78 9 10 int *p = static_cast<int *>(malloc(100)); 11 12 system("pause"); 13 }
11 typeid
在C++中,typeid用于返回指针或引用所指对象的实际类型。
1 #include <iostream> 2 using namespace std; 3 4 void main() 5 { 6 double db(10.9); 7 double *pdb(&db); 8 9 auto num(pdb);//通用传入接口 10 11 std::cout << typeid(db).name() << std::endl;//double 12 std::cout << typeid(pdb).name() << std::endl;//double * 13 std::cout << typeid(num).name() << std::endl;//double * 14 15 system("pause"); 16 }
typeid是根据指针检查类型的,如果类中没有虚函数,那么可能会检测不准确
1类中没有虚函数,检测不准确
直接用基类指针引用基类对象
用基类指针引用一个派生类对象
1 #include <iostream> 2 3 //typeid是根据指针检查类型的,如果类中没有虚函数,那么可能会检测不准确 4 5 class A 6 { 7 public: 8 int num; 9 static int data; 10 void run() 11 { 12 std::cout << "Arun" << std::endl; 13 } 14 }; 15 16 class B :public A 17 { 18 public: 19 int num; 20 static int data; 21 void run() 22 { 23 std::cout << "Brun" << std::endl; 24 } 25 void test() 26 { 27 std::cout << "Btest" << std::endl; 28 } 29 }; 30 31 int A::data = 1; 32 int B::data = 2; 33 34 void main() 35 { 36 A *p1 = new A;//直接用基类指针引用基类对象 37 A *p2 = new B;//用基类指针引用一个派生类对象 38 39 std::cout << typeid(p1).name() << " " << typeid(p2).name() << std::endl;//检查两个指针类型 40 41 std::cout << typeid(*p1).name() << " " << typeid(*p2).name() << std::endl;//检查两个指针指向的类型,实际上是不一样的,但是检测不准确 42 43 std::cout << (typeid(p1) == typeid(p2)) << std::endl;//1,检查两个指针类型 44 45 std::cout << (typeid(*p1) == typeid(*p2)) << std::endl;//1,检查两个指针指向的类型,实际上是不一样的,但是检测不准确 46 47 system("pause"); 48 }
2类中有虚函数,检测准确
直接用基类指针引用基类对象
用基类指针引用一个派生类对象
1 #include <iostream> 2 3 //typeid是根据指针检查类型的,如果类中没有虚函数,那么可能会检测不准确 4 5 class A 6 { 7 public: 8 int num; 9 static int data; 10 virtual void run()//虚函数 11 { 12 std::cout << "Arun" << std::endl; 13 } 14 }; 15 16 class B :public A 17 { 18 public: 19 int num; 20 static int data; 21 virtual void run()//虚函数 22 { 23 std::cout << "Brun" << std::endl; 24 } 25 void test() 26 { 27 std::cout << "Btest" << std::endl; 28 } 29 }; 30 31 int A::data = 1; 32 int B::data = 2; 33 34 void main() 35 { 36 A *p1 = new A;//直接用基类指针引用基类对象 37 A *p2 = new B;//用基类指针引用一个派生类对象 38 39 std::cout << typeid(p1).name() << " " << typeid(p2).name() << std::endl;//检查两个指针类型 40 41 std::cout << typeid(*p1).name() << " " << typeid(*p2).name() << std::endl;//检查两个指针指向的类型 42 43 std::cout << (typeid(p1) == typeid(p2)) << std::endl;//1,检查两个指针类型 44 45 std::cout << (typeid(*p1) == typeid(*p2)) << std::endl;//0,检查两个指针指向的类型 46 47 system("pause"); 48 }