C++——强制类型转化、const的理解

1.C方式强制类型((Type)(a))转换存在的问题

(1)任意类型之间都可以进行转换,编译器很难判断其正确性

(2)在源码中无法快速定位所有使用强制类型转换的语句

C++中的强制类型转换,语法:xxx_cast<Type>(a)

(1)static_cast

用于基本类型间的转换,不能用于基本类型指针间的转换,用于有继承关系类对象之间的转换和类指针之间的转换

(2)const_cast

用于去除变量的只读属性,强制转换的目标类型必须是指针或引用

(3)dynamic_cast

用于有继承关系的类指针间的转换,用于有交叉关系的类指针间的转换,具有类型检查的功能,需要虚函数的支持

通过子类指针去指向父类指针

复制代码
#include <iostream>
using namespace std;
 
class Base
{
public:
    Base()
    {
        cout << "Base::Base()" << endl;
    }
 
    virtual void func()
    {
        cout << "Base::func()" << endl;
    }
 
    virtual ~Base()
    {
        cout << "Base::~Base()" << endl;
    }
 
};
 
class Derived : public Base
{
public:
    virtual void func()
    {
        cout << "Derived::func()" << endl;
    }
 
};
 
int main()
{
    Base* p = new Base;                            //初始化父类指针
 
    Derived* pd = dynamic_cast<Derived*>(p);    //由于父类指针指向的是父类,只有父类虚函数表,没有子类的虚函数表,所以转换失败
                              //如果使用static_cast或者reinterpret_cast,则能成功,调用pd->func则打印Base::func()    
  
    //pd->func();                               //由于pd=0,所以这里会程序崩溃
    cout << "pd = " << pd << endl;              //转换失败,打印 0
 
    delete p;
 
    p = reinterpret_cast<Base*>(new Derived);      //等价于p =  (Base*)new Derived; 或者 p =  reinterpret_cast<Base*>(new Derived)
                              //或者static_cast
 
    pd = dynamic_cast<Derived*>(p);              //由于父类指针指向的是子类,所以有子类虚函数表
    pd->func();                                  //打印"Derived::func()"
    cout <<"pd = " << pd <<endl;                //转换成功,打印地址值
 
    delete p;
 
    return 0;
}
  • 父类(无虚函数)强制转为子类时,可以用static_cast或者reinterpret_cast进行强转

(4)reinterpret_cast

用于指针类型间的转换,用于整数与指针类型间的强转

复制代码
#include <stdio.h>
void staic_cast_demo() {
	int i = 0x12345;
	char c = 'c';
	int* pi = &i;
	char* pc = &c;
	
	c = static_cast<char>(i);
	// pc = static_cast<char*>(pi); //error,不能用于基本类型指针间的转换
}
void const_cast_demo() {
	const int& j = 1; //只读变量
	int& k = const_cast<int&>(j); //去除只读变量,可以通过k修改变量的值
	const int x = 2; //常量,存在符号表里
	int& y = const_cast<int&>(x); //内存会给这个常量分配一个临时的空间,并且y指向这块空间
	// int z = const_cast<int>(x); //error,目标类型必须是指针或引用
	k = 5;
	printf("k=%d\n", k); //5
	printf("j=%d\n", j); //5
	y = 8;
	printf("x=%d\n", x); //2
	printf("y=%d\n", y); //8
	printf("&x=%p\n", &x); //&x=0000006DB754F964
	printf("&y=%p\n", &y); //&y=0000006DB754F964
}
void reinterpret_cast_demo() {
	int i = 0;
	char c = 'c';
	int* pi = &i;
	char* pc = &c;
	pc = reinterpret_cast<char*>(pi);
	pi = reinterpret_cast<int*>(pc);
	pi = reinterpret_cast<int*>(i);
	// c = reinterpret_cast<char>(i); //error,不能用于基本类型间的转换
}
void dynamic_cast_demo() {
	int i = 0;
	int* pi = &i;
	// char* pc = dynamic_cast<char*>(pi); error,只能用于有继承关系的类指针间的转换
}
int main() {
	staic_cast_demo();
	const_cast_demo();
}

2.const什么是只读变量,什么是常量?

(1)只有用字面量初始化的const常量才会进入符号表

const int x=1;

(2)使用其他变量初始化的const常量仍然是只读变量

const int& rx=x;

(3)被volatile修饰的const常量是易变的,因此不会进入符号表

即在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理,只读变量仅仅意味着被const修饰的变量不能出现在赋值符号左边

复制代码
#include <stdio.h>
int main() {
	const int x = 1;
	const int& rx = x;
	int& nrx = const_cast<int&>(rx);
	nrx = 5;
	printf("x=%d\n", x);
	printf("rx=%d\n", rx);
	printf("nrx=%d\n", nrx);
	printf("&x=%d\n", &x);
	printf("&rx=%d\n", &rx);
	printf("&nrx=%d\n", &nrx);

	volatile const int y = 2; //加了volatile就是只读变量
	int* p = const_cast<int*>(&y);
	*p = 6;
	printf("y=%d\n", y); //6
	printf("p=%p\n", p); //p=000000D6682FF8D4

	const int z = y;
	p = const_cast<int*>(&z);
	*p = 7;
	printf("z=%d\n", z);
	printf("p=%p\n", p);

	char c = 'c';
	char& rc = c;
	const int& trc = c; //引用的类型不同,则会生成一个新的只读变量,即trc是只读变量
	rc = 'a';
	printf("c=%c\n", c);
	printf("rc=%c\n", rc);
	printf("trc=%c\n", trc);
}

运行结果:

3.引用与指针的关系

指针:

(1)指针是一个变量,值为一个内存地址,不需要初始化,可以保存不同的地址

(2)通过指针可以访问对应内存地址中的值

(3)指针可以被const修饰为常量或只读变量

引用:

(1)引用只是变量的一个新名字,对引用的操作都会传递到代表的变量

(2)const引用使其代表的变量具有只读属性

(3)引用必须在定义时初始化,之后无法代表其他变量

复制代码
#include <stdio.h>
int main() {
	
    // const 常量
    const int c = 0;    //const局部变量

    int* p = (int*)&c; //使用&操作符,会分配空间      int* p = (int*)&c  -> const int& p = c;

    *p = 5;
    printf("c = %d,*p=%d\n", c, *p);  // c = 0,*p=5 实际没有改变c自身的值。
    
    
    // const 只读变量 (一般用在引用或者指针上)

    int d = 1;          // 临时变量,自身可读写

    const int& p2 = d;   // 其实这个p2 是个只读变量(可以通过const_cast去更改)

    int& p3 = const_cast<int&>(p2);

    p3 = 100;

    printf("d = %d  p2 = %d\n", d, p2);  //d = 100  p2 = 100  实际目标d被改变了,因为d是个可读写的变量。
                                         //所以引用修饰的const只是个标志,到底能不能更改目标,需要引用的目标类型是否是const

    const int d2 = 1;          // 引用的目标类型是const

    const int& p4 = d2;   // 其实这个p4 是个只读变量(可以通过const_cast去更改)

    int& p5 = const_cast<int&>(p4);

    p5 = 100;

    printf("d2 = %d  p4 = %d\n", d2, p4);  //d = 100  p2 = 100  实际目标d2没有改变,因为d2是个常量。 


    return 0;
}
相关推荐
hzb666667 小时前
unictf2026
开发语言·javascript·安全·web安全·php
我在人间贩卖青春7 小时前
C++之面向对象编程多文件文件示例
c++
燃于AC之乐7 小时前
深入解剖STL deque:从源码剖析到容器适配器实现
开发语言·c++·stl·源码剖析·容器实现
kaikaile19957 小时前
基于MATLAB的滑动轴承弹流润滑仿真程序实现
开发语言·matlab
禹凕7 小时前
Python编程——进阶知识(MYSQL引导入门)
开发语言·python·mysql
MSTcheng.7 小时前
【C++】C++异常
java·数据库·c++·异常
草莓熊Lotso8 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
傻乐u兔8 小时前
C语言进阶————指针4
c语言·开发语言
大模型玩家七七8 小时前
基于语义切分 vs 基于结构切分的实际差异
java·开发语言·数据库·安全·batch