剑指offer试题整理1

1、定义一个空的类型,里面没有任何成员变量和成员函数。对该类型求sizeof,得到的结果是什么?

答案:1.

为什么不是0?

空类型的示例中不包含任何信息,本来求siezof应该是0,但是当我们声明改类型的实列是时候,它必须再内存中占有一定的空间,否则无法使用这些实例。
对于至少占用多少内存,这由编译器决定。
在Visual Studio中,每个空类型的实例都占用一字节的空间。
在这里插入图片描述

如果在该类型中添加一个构造函数和析构函数,再对该类型求sizeof,得到的结果优势多少?

还是1。
调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型相关,而与类型的示例无关,编译器也不会因为这两个函数而再示例内添加任何额外的信息。
在这里插入图片描述

那添加一个析构函数呢?如果把析构函数标记为虚函数呢?

C++编译器一旦发现一个类型中由虚函数,就会为该类型生成虚函数表,并在该类型的每一个示例中添加一个指向虚函数表的指针。
在32位的机器上,一个指针占4字节,因此求sizeof得到4;如果是在64位的机器,则一个字节占8字节的空间,因此求sizeof得到8。

在这里插入图片描述

2、

给出以下代码,分析编译器运行的结果:
A、编译错误;
B、编译成功,运行时程序崩溃;
C、编译运行正常,输出10;

class A
{
private:
	int value;
public:
	A(int n){value = n;}
	A(A other){value = other.value;}

	void Print(){std::cout << value << std::endl;}

};

int _tmain(int argc,_TCHAR *argv[])
{
	A a = 10;
	A b = a;
	b.Print();

	return 0;
}

在上述代码中,复制构造函数A(A other)传入的参数是A的一个实例。由于是传值参数,我们把形参复制到实参会调用复制构造函数。因此,如果允许复制构造函数传值,就会在复制构造函数内调用复制构造函数,就会形成永无休止的递归调用从而导致栈溢出。因此,C++的标准不允许复制构造函数传值参数,在 Visual Studio和 GCC中,都将编译出错。要解决这个问题,我们可以把构造函数修改为A(const A& other),也就是把传值参数改成常量引用。

在这里插入图片描述
在这里插入图片描述

3、赋值运算符函数

题目:如下为类型CMyString 的声明,请为该类型添加赋值运算符函数。

class CMyString
{
public:
	CMyString(char *pData = nullptr);	
	CMyString(const CMyString& str);
	~CMyString(void);
	
private:
	char* m_pData;
};

经典解法:

CMyString& CMyString::operator =(const CMyString &str)
{
	//判断自赋值
	if(this == &str)
		return *this;

	//先释放左值
	delete[]m_pData;
	m_pData = nullptr;

	//开辟右值空间大小
	m_pData = new char[strlen(str.m_pData) + 1];

	//拷贝赋值
	strcpy_s(m_pData,strlen(str.m_pData) + 1,str.m_pData);

	//返回引用
	return *this;
}

考虑异常安全性的解法

在经典解法中,我们在分配内存之前先调用了delete 释放了实例 m_pData 的内存。但如果此时的内存不足,导致new char 抛出异常,则 m_pData 将是一个空指针,这样很容易导致程序崩溃。
即,一旦在赋值运算符函数内部抛出一个异常,CMyString的实例不再保持有效的状态,这就违背了安全性原则。

要想在赋值运算符函数中实现异常安全性,有两种方法:
一种简单的办法是我们先用new 分配新内容,再用 delete释放已有的内容。这样只在分配内容成功之后再释放原来的内容,也就是当分配内存失败时我们能确保 CMyString的实例不会被修改。
我们还有一种更好的办法,即先创建一个临时实例,再交换临时实例和原来的实例。下面是这种思路的参考代码:

	CMyString& CMyString::operator =(const CMyString &str)
	{
		if(this != &str)
		{
			//创建一个临时实例strTemp,在当前{}结束后,会自动调用自己的析构函数释放相关内存
			CMyString strTemp(str);

			//把strTemp.m_pData 和实例自身的m_pData进行交换  当临时变量strTemp析构时,因为进行了交换,所以会释放原来p_Data的内存
			char* pTemp = strTemp.m_pData; 
			strTemp.m_pData = m_pData;
			m_pData = pTemp;
		}

		return *this;
	}

4、在C/C++中,struct和class的区别?

C++中类和结构体的区别:

默认的防控属性(访问控制)不同,struct是public的,而class是private的。

C中结构体和C++结构体区别:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值