IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++ 知识点(不断更新) -> 正文阅读

[C++知识库]c++ 知识点(不断更新)

const

class A {
private:
	const int a;//常对象成员,可以使用初始化列表或者类内初始化
public:
	//构造函数
	A() :a(0) {};
	A(int x) :a(x) {};//初始化列表

	//const可用于对重载函数的区分
	int getValue();//普通成员函数
	int getValue() const;//常成员函数,不得修改类中任何数据成员的值
};

void function()
{
	//对象
	A b;//普通对象,可以调用全部成员函数
	const A a;//常对象,只能调用常成员函数
	const A *p = &a;//指针变量,指向常对象
	const A &q = a;//指向常对象的引用

	//指针
	char greeting[] = "Hello";
	char *p1 = greeting;//指针变量,指向字符数组变量			注:指针指向数组不需要加&,它本身就是地址
	const char* p2 = greeting;//指针变量,指向字符数组常量		注:const后面是char,说明char不能改变
	char* const p3 = greeting;//指针常量,指向字符数组变量		注:const后面是p3指针,说明指针不能改变
	const char* const p4 = greeting;//指针常量,指向字符数组常量
}

//函数
void function1(const int Var);//传递过来的参数在函数内不可变
void function2(const char* Var);//参数指针所指的内容为常量
void function3(char* const Var);//参数指针为常量
void function4(const int& Var);//引用参数在函数内为常量

//函数返回值
const int function5();//返回一个常量
const int* function6();//返回一个指向常量的指针变量。使用const int* p =function6();
int* const function7();//返回一个指向量的常针。使用 int* const p =function7();

没有const &a,引用只是对象的别名,不是对象,不能用const修饰

static

  1. 修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它。

  2. 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。

  3. 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。

  4. 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。

class Point  
{  
public:   
    void init()  
    {    
    }  
    static void output()  
    {  
    }  
};  
void main()  
{  
    Point::init();  //error
    Point::output();  //succeed,饰成员函数使得不需要生成对象就可以访问该函数
}
class Point  
{  
public:   
    void init()  
    {    
    }  
    static void output()  
    {  
        printf("%d\n", m_x);  //error ,static 函数内不能访问非静态成员。
        //因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。反之,类的非静态成员函数可以调用用静态成员函数。
    }  
private:  
    int m_x;  
};  
void main()  
{  
    Point pt;  
    pt.output();  
}

this指针

this指针是一个隐含在每一个非静态成员函数中的特殊指针,指向调用该成员函数的那个对象。
常需要显式使用this指针的情况:1.实现对象的链式引用;2.避免对同一对象进行赋值操作;3.实现一些数据结构,如 list 。

inline内联函数

不用进入函数,直接执行函数体,提高效率
类内定义的函数,除了虚函数,都默认为内联函数
相当于把内联函数体复制到内联函数调用点处,消耗内存空间

class A {
	int doA() { return 0; }//类内定义,隐式内联
};

class B {
	int doB();
};
inline int B::doB() { return 0; }//类外定义,显式内联

虚函数的内联
虚函数可以是内联函数,但是当虚函数是多态时不能内联。因为多态在运行期执行,内敛在编译期执行,编译器不知道运行期调用哪个代码。
inline virtual 唯一可行的时候是:编译器知道所调用的对象是哪个类,这只有在编译器拥有实际对象而非对象的引用或指针时才会发生

class Base {
public:
	inline virtual void who()
	{
		cout << "I am Base\n";
	}
	virtual ~Base() {}
};

class Derived:public Base{
public:
	inline void who()//不写inline隐式内联
	{
		cout << "I am Dervied\n";
	}
};
int main() {
	//此处的虚函数是通过Base类的具体对象b调用的,编译期可确定,所以他是内联的
	Base b;
	b.who();

	//此处的虚函数是通过指针调用的,呈多态性,需要在运行期间才能确定,所以不能内联
	Base *ptr = new Derived();
	ptr->who();

	//因为Base有虚析构函数,所以delete的时候先调用派生类derived的析构函数,然后调用基类Base的析构函数,防止内存泄漏
	delete ptr;
	ptr = nullptr;

	system("pause");
	return 0;
}

volatile

volatile是一种类型修改符,用它声明的类型表示可以被某些未知因素修改(操作系统,硬件,其他线程),编译期不应对这样的对象优化。
volatile关键字声明的变量,每次都要从内存中取值
const可以是volatile
指针可以是volatile

volatile int i = 0;
volatile char* vpch;
char* volatile pchv;

assert()

是一个宏,而非函数。
作用是:如果条件返回错误,则终止程序执行

#define NDEBUG //在 #include <cassert> 前加上这行 则assert被禁用
#include <cassert>
assert(p != NULL);//p为空 返回错误

sizeof()

对数组使用,得到整个数组所占的空间大小
对指针使用,得到指针本身所占的空间大小

#pragma pack(n)

设定结构体,联合以及类成员变量以n字节对齐

#pragma pack(push)//保存对其状态
#pragma pack(4)//设定为4字节对齐

struct test {
	char m1;//4   1+3对齐
	double m4;//8  4的倍数不需要变 
	int m3;//4
	//4+8+4=16字节
};

#pragma pack(pop);//恢复对齐状态

位域

类为非静态成员函数定义位域,占多少个二进制位,可节省一定内存
指针和取地址不可作用于位域

Bit mode 2;//mode占两位

extern C

被extern修饰的变量是extern类型的
被extern "C"修饰的变量表示用C语言处理当前代码
防止c++代码修改和c语言不匹配

#ifdef __cplusplus
extern "C"{
#endif
void *meset(void*,int,size_t);
#ifdef __cplusplus
}
#endif

struct和typedef struct

c中

typedef struct Student{
	int age;
} S;
//等价于
struct Student{
	int age;
};
typedef struct Student S;

void Student(){}//和struct不冲突

c++中

struct Student{
	int age;
};
void f1(Student me);//struct 可省略
void f2(struct Student me);
typedef struct Student{
	int age;
}S;
void Student(){}//正确 此后Student只代表此函数,不代表结构体
void S(){}//错误 S是struct Student的别名
int main(){
	Student();//调用函数
	struct Student me;
	//or S me;
	return 0;
}

struct & class

struct适合看作数据结构的实现体,class适合看作对象的实现体
默认的访问权限:class是private,struct是public

union联合

一种节省空间的特殊的类,可以拥有很多数据结构,但在同一时刻只能有一个数据成员有值,其他数据成员变成未定义状态。
默认访问权限为public
可以包含构造函数和析构函数
不能含有引用类型的成员
不能继承自其他类,不能作为基类
不能含有虚函数
匿名union在定义所在的作用域可以直接访问union成员
匿名union不能包含protect,private成员
全局匿名union必须是static静态的

//联合体
union UnionTest
{
	UnionTest() :i(10) {};
	int i;
	double d;
};

//全局静态匿名union
static union {
	int i;
	double d;
};

int main()
{
	UnionTest u;

	//局部匿名union
	union {
		int i;
		double d;
	};

	cout << u.i << endl;//输出 UnionTest联合体  10

	::i = 20;
	cout << ::i << endl;//输出 全局静态匿名联合体  20

	i = 30;
	cout << i << endl;//输出局部匿名联合体  30
	return 0;
}

c实现c++面向对象特性

封装:使用函数指针将属性和方法封装到结构体中
继承:结构体嵌套
多态:父类和子类的函数指针不同

expliit(显示)关键字

explicit修饰构造函数时,可以防止隐式转换和复制初始化
explicit修饰转换函数时,可以防止隐式转换,按语境转换除外

下列语境中,期待类型 bool,且若声明 bool t(e); 良构则进行隐式转换(即考虑如 explicit T::operator bool() const; 这样的隐式转换函数)。称这种表达式 e 按语境转换为 bool。
if、while、for 的控制表达式;
内建逻辑运算符 !、&& 和 || 的操作数;
条件运算符 ?: 的首个操作数;
static_assert 声明中的谓词;
noexcept 说明符中的表达式;

struct A {
	A(int) {}
	operator bool()const { return true; }
};
struct B {
	explicit B(int) {}
	explicit operator bool()const { return true; }
};
void doA(A a) {}
void doB(B b) {}

int main() {
	A a1(1);//直接初始化
	A a2 = 1;//复制初始化
	A a3{ 1 };//直接列表初始化
	A a4 = { 1 };//复制列表初始化
	A a5 = (A)1;//static_cast显示转换
	doA(1);//int到A的隐式转换
	if (a1);//转换函数A::operator bool()的从A到bool的隐式转换
	bool a6(a1);//转换函数A::operator bool()的从A到bool的隐式转换
	bool a7 = a1;//转换函数A::operator bool()的从A到bool的隐式转换
	bool a8 = static_cast<bool>(a1);//static_cast 直接进行初始化

	B b1(1);
	B b2 = 1;//error  explicit不可以复制初始化
	B b3{ 1 };
	B b4 = { 1 };//error  explicit不可以复制列表初始化
	B b5 = (B)1;
	doB(1);//error  explicit不可以int到B隐式转换
	if (b1);//按语境转换
	bool b6(b1);//按语境转换
	bool b7 = b1;//error  explicit不可以隐式转换
	bool b8 = static_cast<bool>(b1);//static_cast 直接进行初始化
	return 0;
}

friend 友元类和友元函数

能访问private成员
破坏封装性
友元关系不可传递
友元关系是单向的
友元声明的形式和数量不受限制

class CCar
{
private:
    int price;
    friend class CDriver;  //声明 CDriver 为友元类
};
class CDriver
{
public:
    CCar myCar;
    void ModifyCar()  //改装汽车
    {
        myCar.price += 1000;  //因CDriver是CCar的友元类,故此处可以访问其私有成员
    }
};
class CCar;  //提前声明CCar类,以便后面的CDriver类使用
class CDriver
{
public:
    void ModifyCar(CCar* pCar);  //改装汽车
};
class CCar
{
private:
    int price;
    friend int MostExpensiveCar(CCar cars[], int total);  //声明友元
    friend void CDriver::ModifyCar(CCar* pCar);  //声明友元
};
void CDriver::ModifyCar(CCar* pCar)
{
    pCar->price += 1000;  //汽车改装后价值增加
}
int MostExpensiveCar(CCar cars[], int total)  //求最贵气车的价格
{
    int tmpMax = -1;
    for (int i = 0; i<total; ++i)
        if (cars[i].price > tmpMax)
            tmpMax = cars[i].price;
    return tmpMax;
}

using

  1. using声明
    一条using声明一次只能引入命名空间的一个成员
    using namespace_name::name
  2. 构造函数的using声明
    派生类可以重用其直接基类定义的构造函数,编译器生成每个构造函数对应的派生类构造函数
class Derived:Base{
public:
	using Base::Base;
}

尽量少使用using指示,污染命名空间(导入的名字过多可能重名,发生覆盖)

using namespace std;

多使用using声明

int x;
std::cin>>x;
std::cout<<x<<std::endl;

or

using std::cin;
using std::cout;
using std::endl;
int x;
cin>>x;
cout<<x<<endl;

::范围解析运算符

  1. 全局作用域符::name:用于类型名称(类,类成员,成员函数,变量等)前,表示作用域为全局命名空间
  2. 类作用域符class::name:用于表示指定类型的作用域时某个具体的类
  3. 命名空间作用域符namespace::name:用于表示指定类型的作用域时某个命名空间
int count = 11;//全局 ::

class A {
public:
	static int count;//类 class_name::count
};
int A::count = 21;

void fun() {
	int count = 31;//初始化局部的count为31
	count = 32;//设置局部的count为32
}

int main() {
	::count = 12;//设置全局的count为12
	A::count = 22;//设置类A的count为22
	fun();//函数局部的count为32
	return 0;
}

enum枚举类型

  1. 限定作用域的枚举类型
enum class open_modes{input,output,append};
  1. 不限定作用域的枚举类型
enum color{red,yellow,green};
enum{floatPrec=6,double=10};

decltype

用于检查实体的声明类型或表达式的类型及值分类
decltype(expression)

template <typename It>
auto fcn(It beg, It end)->decltype(*beg) 尾置返回允许我们在参数列表之后声明返回类型
{
	//处理序列
	return *beg;//返回序列中一个元素的引用
}
//为了使用参数模板成员,必须用typename
template <typename It>
auto fcn2(It beg,It end)->typename remove_reference<decltype(*beg)>::type
{
	return *beg;//返回序列中一个元素的拷贝
}
#include <string>
using namespace std;
class Student{
public:
    static int total;
    string name;
    int age;
    float scores;
};
int Student::total = 0;
int  main(){
    int n = 0;
    const int &r = n;
    Student stu;
    decltype(n) a = n;  //n 为 int 类型,a 被推导为 int 类型
    decltype(r) b = n;     //r 为 const int& 类型, b 被推导为 const int& 类型
    decltype(Student::total) c = 0;  //total 为类 Student 的一个 int 类型的成员变量,c 被推导为 int 类型
    decltype(stu.name) url = "abcdefg";  //total 为类 Student 的一个 string 类型的成员变量, url 被推导为 string 类型
    return 0;
}

引用

  1. 左值引用
    常规引用,一般表示对象的身份
  2. 右值引用
    右值引用就是必须绑定到右值(一个临时对象、将要销毁的对象)的引用,一般表示对象的值。

右值引用可实现转移语义(Move Sementics)和精确传递(Perfect Forwarding),它的主要目的有两个方面:
消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
能够更简洁明确地定义泛型函数。

  1. 引用折叠
    X& &、X& &&、X&& & 可折叠成 X&
    X&& && 可折叠成 X&&

#define xxx
#define Max(x,y) ((x)>(y)?(x):(y))
宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对 “参数” 进行的是一对一的替换。

成员初始化列表

效率高,少一次调用默认构造的过程.

有些场合必须要用初始化列表:
常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化

initializer_list 列表初始化


#include <iostream>
#include <vector>
#include <initializer_list>

template<class T>
struct S {
	std::vector<T> v;
	S(std::initializer_list<T> l) :v(l) {
		std::cout << "constructed with a" << l.size() << "-element list";
	}

	void append(std::initializer_list<T>l) {
		v.insert(v.end(), l.begin(), l.end());
	}

	std::pair<const T*, std::size_t>c_arr()const {
		return{ &v[0],v.size() };//c_arr().first  ==&v[0]   c_arr().second  ==v.size()
	}
};

template <typename T>
void templated_fn(T) {}

int main() {
	S<int>s1 = { 1,2,3,4,5 };//复制初始化
	S<int>s2{ 1,2,3,4,5 };//直接初始化
	s1.append({ 6,7,8 });//列表初始化

	std::cout << "The vector size now is" << s.c_arr().second << "ints:\n";

	for (auto n : s.v) {
		std::cout << n << ' ';
	}
	std::cout << "\n";

	std::cout << "Range-for over brace-init-list: \n";
	
	for (int x : {-1, -2, -3}) {
		std::cout << x << ' ';
	}
	std::cout << '\n';

	auto al = { 10,11,12 };
	std::cout << "The list bound to auto has size() = " << al.size() << '\n';

	//    templated_fn({1, 2, 3}); // 编译错误!“ {1, 2, 3} ”不是表达式,
								 // 它无类型,故 T 无法推导
	templated_fn<std::initializer_list<int>>({ 1, 2, 3 }); // OK
	templated_fn<std::vector<int>>({ 1, 2, 3 });           // 也 OK
}

面向对象

在这里插入图片描述

封装

把客观的事物封装成抽象的类,类可以把自己的数据做出公开,隐藏或者对朋友公开.
关键字:
public:可被任意实体访问
private:可被本类或者友元访问
protected:只能被本类和子类访问

继承

基类(父类)–>派生类(子类)

多态

以封装和继承为基础
分类及实现

  1. 重载多态:函数重载,运算符重载
  2. 子类型多态:虚函数
  3. 参数多态性:类模板,函数模板
  4. 强制多态:基本类型转换,自定义类型转换

静态多态

函数重载

class A
{
public:
	void do(int a);
	void do(int a,int b);
};

动态多态

虚函数:virtual修饰成员函数
动态绑定:当使用基类的引用或指针调用一个虚函数时发生动态绑定.

可以将派生类的对象赋值给基类的指针或引用,反之不可
普通函数(非类成员函数)不能是虚函数
静态函数(static)不能是虚函数
构造函数不能是虚函数(因为在调用构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针)
析构函数可以是虚函数,为了解决基类指针指向子类并删除的内存泄漏问题
内联函数不能是表现多态性时的虚函数

class Shape
{
public:
	//virtual Shape();  error 构造函数不能是虚函数
	virtual double calcArea() {}
	virtual ~Shape() {};//虚函数可以是虚函数
};

class Circle :public Shape
{
public:
	virtual double calcArea() {};
};

class Rect :public Shape
{
public:
	virtual double calcArea() {};
};
int main()
{
	Circle *c1 = new Circle();
	Shape* s1 = c1;//父类指针可以指向子类

	Shape* s2 = new Circle();
	s2->calcArea();

	delete c1;//c1是子类的指针,析构时只调用自己的析构函数
	c1 = nullptr;
	delete s1;//s1是父类的指针,析构时先调用子类的析构 后调用父类的析构函数,防止内存泄漏
	s1 = nullptr;
	delete s2;
	s2 = nullptr;

	Shape* S3 = new Shape();
	//Rect*r1 = S3;  error 子类指针不能指向父类
	//Rect*r2 = new Shape();  error
}

纯虚函数

在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做
virtual int A()=0;
最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”;

虚函数、纯虚函数
类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被覆盖(override),这样的话,编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
虚函数在子类里面可以不重写;但纯虚函数必须在子类实现才可以实例化子类。
虚函数的类用于 “实作继承”,继承接口的同时也继承了父类的实现。纯虚函数关注的是接口的统一性,实现由子类完成。
带纯虚函数的类叫抽象类,这种类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。抽象类被继承后,子类可以继续是抽象类,也可以是普通类。
虚基类是虚继承中的基类

虚函数指针,虚函数表

虚函数表:在程序只读数据段,存放虚函数指针,如果派生类实现了基类的某个虚函数,则在虚表中覆盖原本基类的那个虚函数指针,在编译时根据类的声明创建。
虚函数指针:在含有虚函数类的对象中,指向虚函数,在运行时确定。

虚继承

虚继承、虚函数
相同之处:

  1. 都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)

不同之处:

  1. 虚继承
    虚基类依旧存在继承类中,只占用存储空间
    虚基类表存储的是虚基类相对直接继承类的偏移
  2. 虚函数
    虚函数不占用存储空间
    虚函数表存储的是虚函数地址

模板类、成员模板、虚函数

类模板中可以有虚函数
一个类的成员模板函数不能是虚函数

抽象类、接口类、聚合类

抽象类:含有纯虚函数的类
接口类:仅含有纯虚函数的抽象类
聚合类:用户可以直接访问其成员,并且具有特殊的初始化语法形式。满足如下特点:
所有成员都是 public
没有定义任何构造函数
没有类内初始化
没有基类,也没有 virtual 函数

内存分配和管理

  1. malloc、calloc、realloc、alloca
    malloc:申请指定字节数的内存。申请到的内存中的初始值不确定。
    calloc:为指定长度的对象,分配能容纳其指定个数的内存。申请到的内存的每一位(bit)都初始化为 0。
    realloc:更改以前分配的内存长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定。
    alloca:在栈上申请内存。程序在出栈的时候,会自动释放内存。

  2. malloc free 分配释放内存

char *str=(char*)malloc(100);
assert(str!=nullptr);//确认是否申请成功
free(str);
str =nullptr;
  1. new delete
    new/new[] 先调用malloc分配内存后调用构造函数
    delete/delete[] 先调用析构函数后free释放空间
int main()
{
	T* t= new T();
	delete t;
	return 0;
}

new可以自己计算所需要的空间来分配,malloc需要自己输入申请空间的字节数

  1. 定位new
    向new传递地址参数,从而预先在指定的内存区域创建对象
new (place_address) type
new (place_address) type (initializers)
new (place_address) type [size]
new (place_address) type [size] { braced initializer list }
int main(){
	char buffer[512];
	int *p1 = new (buffer) int[10];//定位
	int *p2 = new int[10];//常规
}

定义一个只能在堆上(栈上)生成对象的类

只能在堆上
方法:将析构函数设置为私有

只能在栈上
方法:将 new 和 delete 重载为私有

智能指针

c++11有三种智能指针

shared_ptr 实现共享式拥有概念。多个智能指针指向相同对象,该对象和其相关资源会在 “最后一个 reference 被销毁” 时被释放。

weak_ptr 允许你共享但不拥有某对象,一旦最末一个拥有该对象的智能指针失去了所有权,任何 weak_ptr 都会自动成空。可打破环状引用,解决死锁问题

unique_ptr 实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。你可以移交拥有权。一旦拥有着被销毁或编程 empty,或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。它对于避免内存泄漏——如 new 后忘记 delete ——特别有用。unique_ptr 用于取代旧版本的 auto_ptr

强制类型转换运算符

  1. static_cast
    用于非多态类型的转换
    不执行运行时类型检查(转换安全性不如 dynamic_cast)
    通常用于转换数值数据类型(如 float -> int)
    可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法)
    向上转换是一种隐式转换。

  2. dynamic_cast
    用于多态类型的转换
    执行行运行时类型检查
    只适用于指针或引用
    对不明确的指针的转换将失败(返回 nullptr),但不引发异常
    可以在整个类层次结构中移动指针,包括向上转换、向下转换

  3. const_cast
    用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )

  4. reinterpret_cast
    用于位的简单重新解释
    滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。
    允许将任何指针转换为任何其他指针类型(如 char* 到 int* 或 One_class* 到 Unrelated_class* 之类的转换,但其本身并不安全)
    也允许将任何整数类型转换为任何指针类型以及反向转换。
    reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。
    reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。

  5. bad_cast
    由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常。
    bad_cast 使用

try {  
    Circle& ref_circle = dynamic_cast<Circle&>(ref_shape);   
}  
catch (bad_cast b) {  
    cout << "Caught: " << b.what();  
} 

运行时类型信息 (RTTI)

typeid、type_info 使用

#include <iostream>
using std::cout;

class Flyable {
public:
	virtual void takeoff() = 0;
	virtual void land() = 0;
};

class Bird :public Flyable {
public:
	void foraging() {}
	virtual void takeoff() {}
	virtual void land() {}
	virtual ~Bird() {}
};

class Plane :public Flyable {
public:
	void carry() {}
	virtual void takeoff() {}
	virtual void land() {}
};

class type_info {
public:
	const char* name()const;
	bool operator ==(const type_info & rhs)const;
	bool operator !=(const type_info & rhs)const;
	int before(const type_info & rhs)const;
	virtual ~type_info() {};
};

void doSomething(Flyable *obj) {
	obj->takeoff();
	cout << typeid(*obj).name() << endl;//typeid允许在运行时确定对象的类型,输出class Bird or class Plane  如果想通过基类的指针获得派生类的数据类型,基类必须带有虚函数
	if (typeid(*obj)==typeid(Bird))
	{
		Bird *bird = dynamic_cast<Bird*>(obj);//对象转换
		bird->foraging();
	}

	obj->land();
}

int main() {
	Bird *b = new Bird();
	doSomething(b);
	delete b;
	b = nullptr;
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 09:54:07  更:2021-09-18 09:58:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:04:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码