剑指offer【1】——C++类型转换关键字浅析,空类型sizeof

本文详细介绍了C++中的四种类型转换关键字:static_cast、const_cast、dynamic_cast和reinterpret_cast的特点及应用场景,并探讨了不同情况下类类型的sizeof值。

1、C++有哪四个类型转换的关键字?各有什么特点?分别在什么场景下使用?

**c语言的强制类型转换:**可以对基本数据类型进行类型转换,窄数据类型向宽数据类型转换是安全的,宽数据类型向窄数据类型转换是不安全的,可能损失精度。格式是如下:

TYPE1 a=(TYPE2) b;

**static_cast:**除了可以实现C语言强制数据类型转换相同的基本数据类型的转换外,还可以实现对象类型的转换,其中转换的两个类型必须是继承关系,上行转换(子类向基类转化)是安全的,下行转换时不安全的。static_cast不能修改原变量的const,volatile属性。格式如下:

 TYPE1 a=static_cast<TYPE2>(b);

**const_cast:**用于修改变量的const和volatile属性,常量指针被转化成非常量的指针,并且仍然指向原来的对象;常量引用被转换成非常量的引用,并且仍然指向原来的对象;const_cast一般用于修改底指针,如const char *p形式。格式如下:

const TYPE b;
TYPE *a=const_cast<TYPE*>(&b);
TYPE &c=const_cast<TYPE&>(b);//如果是类类型,对a和c的改变就是对b的改变,如果是基本数据
                             //类型,对a和c的改变不影响b的值(亲测是这样)。


//一个实例:
#include <iostream>
class A{
public:
	A(int t) :i(t){};
	int i;
};

int main(){
	const A a(10);
	A *b = const_cast<A*>(&a);
	A &c = const_cast<A&>(a);
	//a.a = 100;   //不能进行修改,因为A是const
	std::cout << a.i << std::endl;
	b->i = 11;   //同时也改变了a的成员
	std::cout << a.i <<"    "<<b->i<< std::endl;
	c.i = 12;
	std::cout << a.i <<"    "<<c.i<< std::endl;
}
//输出为:
//10
//11    11
//12    12

**dynamic_cast:**在子类和父类之间转换,可以在继承关系、兄弟关系或对象与void*之间进行转换,上行转换(子类向基类转化)是安全的,这个与static_cast一样,下行转换static_cast是不安全的,但是dynamic_cast实在运行时进行动态转换,同时会进行安全检查,下行转换将返回一个空指针。dynamic_cast还支持交叉转换,即在兄弟类型间进行转换,转换个结果为空指针。值得注意的是,dynamic_cast转换的父类必须含有虚函数,因为运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中。格式如下:

//上下行转换
classB
{
public:
int m_iNum;
virtual void foo();
};
 
classD:public B
{
public:
char* m_szName[100];
};
 
void func(B* pb,D* ptr)
{
//上行转换是安全的
D* pd1=static_cast<D*>(pb);
D* pd2=dynamic_cast<D*>(pb);
//下行转换static_cast是不安全的,dynamic_cast是相对安全的
B* ptr1=static_cast<B*>(ptr);   //不安全
B* ptr2=dynamic_cast<B*>(ptr);   //null pointer

}


//交叉转换
classA
{
public:
intm_iNum;
virtual void f(){}
};
class B:public A
{
};
class D:public A
{
};
void foo()
{
B*pb=newB;
pb->m_iNum=100;
//D*pd1=static_cast<D*>(pb);//compile error
D*pd2=dynamic_cast<D*>(pb);//pd2 is NULL
delete pb;
}

**reinterpret_cast:**可以在指针、引用、算术类型、函数指针或者成员指针和整数间进行相互转换,它只是将底层的比特模型重新解释成目标类型,不会对比特进行改变,所以是不安全的,只是为了故弄玄虚和其他目的。

class A {
    public:
    int m_a;
};
class B {
    public:
    int m_b;
};
class C : public A, public B {};
//那么对于以下代码:
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
//前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子
//类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),
//而reinterpret_cast却不会做这一层转换。

2、关于类类型的sizeof

① 问:定义一个空类型,没有成员变量和成员函数,它的sizeof是多少?

struct A{};

std::cout<<sizeof(A);

答:1,空类型的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例的时候,它必须在内存中占有一定空间,否则无法使用这些实例,至于占用多少内存,由编译器决定,Visual Studio每个空类型的实例占一个字节空间。
② 问:如果在类型中添加一个构造函数和一个析构函数,它的sizeof是多少?

struct A{
public:
  A(){}
  ~A(){}
};
std::cout<<sizeof(A);

答:和前面一样,是1,调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型相关,而与类型的实例无关,编译器也不会因为这两个函数而在实例内添加任何额外信息。

③ 问:如果把析构函数标记为虚函数呢?

struct A{
public:
  A(){}
  virtual ~A(){}
};
std::cout<<sizeof(A);

答:是一个指针的大小(32位系统上是4,64位系统上是8)。C++编译器发现一个类型中有虚函数,就会为该类型生成虚表,并在该类型的每一个实例中添加一个指向虚表的指针(**注意:**只有一个指针,而不是每个虚函数一个指针,因为虚表是一个数组,只需要指向数组首元素,就可以遍历所有元素;**补充:**虚函数是为了实现多态而出现的,而虚函数的实现在C++中没有定义,实现方式由编译器决定,一般都是用虚表实现的,虚表存放的位置可参考vicness的专栏)。

01、数据简介 出口韧性是地级市在面对外部震荡和压力时,能够承受并迅速适应、应对变化的能力。这种能力体现在地级市经济结构的灵活性、创新能力和竞争力,以及地方政府的政策支持和产业调整能力等多个方面。 城市出口韧性对于城市的经济发展、就业稳定、国际贸易地位以及风险抵御能力等方面都具有重要影响。因此,城市应加强出口韧性的建设,提高应对外部冲击的能力,以推动其经济的可持续发展。 数据名称:地级市-城市出口韧性数据 数据年份:2011-2022年 02、相关数据 代码 年份 地区 城市 省份 城市出口韧性 距离港口的最近距离 最终进口额_百万人民币2 最终出口额_百万人民币2 人均道路面积2 年末金融机构各项贷款余额万元2 地区生产总值万元2 科学支出万元2 地方财政一般预算内支出万元2 城镇居民人均可支配收入元2 固定资产投资2 实际使用外商投资额百万美元2 城镇化率2 外贸依存度 出口贸易 年平均汇率 实际使用外商投资额百万人民币2 外资依存度 金融发展水平 财政投资力度 科学技术水平 出口偏离度 x_地区生产总值万元2 x_城镇化率2 x_人均道路面积2 x_外贸依存度 x_出口贸易 x_出口偏离度 x_金融发展水平 x_城镇居民人均可支配收入元2 x_财政投资力度 x_科学技术水平 x_距离港口的最近距离 x_外资依存度 地区生产总值万元2_sum y_地区生产总值万元2 城镇化率2_sum y_城镇化率2 人均道路面积2_sum y_人均道路面积2 外贸依存度_sum y_外贸依存度 出口贸易_sum y_出口贸易 出口偏离度_sum y_出口偏离度 金融发展水平_sum y_金融发展水平 城镇居民人均可支配收入元2_sum y_城镇居民人均可支配收入元2 财政投资力度_sum y_财政投资力度 科学技术水平_sum y_科学技术水平
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值