C和C++面试秘笈六——C++面向对象(2)

一、C++中的空类默认会产生哪些类成员函数

我们来看一个空类

class Empty
{
};

这个类中没有定义任何成员,但是为了进行一些默认操作,编译器会给我们加入一些成员函数。

1、默认构造函数,和默认拷贝构造函数,它们被用于类的对象的构造过程。

2、析构函数,它们别用于类的对象的析构过程。

3、赋值函数,它们被用于同类的对象间的赋值过程。

4、取值运算,当对类的对象进行取址(&)时,此函数被调用。

二、explicit构造函数和普通构造函数的区别

C++中explicit关键字是用来修饰类的构造函数的,这个类的构造函数只能带有一个参数,它的作用是用来防止隐式转换的,只能以显示的方式进行类型转换。也就是说explicit构造函数只能被显示的调用

看下面的示例

#include <iostream>

using namespace std;

class Test1
{
public:
	Test1(int n) { num = n; }
private:
	int num;
};

class Test2
{
public:
	explicit Test2(int n) { num = n; }
private:
	int num;
};

int main()
{
	Test1 t1 = 12;
	Test2 t2 = 12;

	system("pause");
	return 0;
}

我们定义了两个类Test1和Test2,在Test2的构造函数前加了explicit关键字,所以上面的代码,t2那一行就会报错,因为explicit不允许隐式的类型转换。所以应该改为 Test2 t2(12); 

区别:

普通的构造函数能够被隐式的调用。

explicit构造函数不能被隐式的调用。

三、拷贝构造函数和赋值函数的区别

类里面的赋值函数也就是=号运算符重载

它们两者有三个方面的区别

1、拷贝构造函数是一个类对象来初始化一块内存区域,这块内存就是新对象的内存区。

     赋值函数是对于一个已经被初始化的对象来进行operator=操作。

2、一般来说是在数据成员包含指针对象的时候,应付两种不同的处理需求:一种是复制指针对象,一种是引用指针对象

     拷贝构造函数在大多数情况下是复制指针对象

     赋值函数是引用指针对象

3、实现不一样

      拷贝构造函数是一个构造函数,它调用的时候是通过参数传递进来的那个对象来初始化产生一个对象。

      赋值函数则是把一个对象赋值给一个原有的对象,所以原来的对象中如果有内存分配首先要把内存释放掉,还要检查一下这两个对象是不是同一个对象,如果是同一个对象,就不需要做任何操作。

四、编写类String的构造函数、析构函数和赋值函数

这题主要考察我们对类的构造函数包括拷贝构造函数、析构函数,以及运算符重载的理解与运用。

#include <iostream>
#include <cstring>
#pragma warning(disable:4996) //因为vs2015中直接使用strcpy编译会报错,
                              //它认为strcpy是不安全的,建议使用strcpy_s,
using namespace std;          //所以加了上面这条语句就可以使用strcpy了

class String
{
public:
	String(const char *str = NULL);    //普通的构造函数
	String(const String &other);       //拷贝构造函数
	~String();                         //析构函数
	String & operator=(const String &other); // 赋值函数,=号运算符重载
	void print() { cout << m_String << endl; }
private:
	char *m_String;
};

String::String(const char *str)
{
	if (NULL == str)             //如果str是空,就存空串“”
	{
		m_String = new char[1];    //分配一个字节
		*m_String = '\0';           //将它赋值为字符串结束符
	}
	else                     //如果不是空,就将str复制到私有成员m_String;
	{
		m_String = new char[strlen(str) + 1];
		strcpy(m_String, str);
	}
}

String::~String()
{
	if (m_String != NULL)    //如果m_String不为空就释放内存
	{                        //并将其置为NULL;
		delete[] m_String;
		m_String = NULL;
	}
}

String::String(const String &other)
{
	m_String = new char[strlen(other.m_String) + 1];  //分配空间来容纳拷贝的字符串
	strcpy(m_String, other.m_String);    //将另一个对象中的m_String复制到此对象的m_String中
}


String & String::operator=(const String &other)
{
	if (this == &other)    //如果对象和other是同一个对象,那么就返回这个对象
	{
		return *this;        
	}

	delete[] m_String;   //如果不是同一个对象,那么就将此对象中的m_String释放内存
	m_String = new char[strlen(other.m_String) + 1]; //然后再为m_String分配一个空间,让其能够容纳
	strcpy(m_String, other.m_String);                //other对象中的m_String。

	return *this;
}

int main()
{
	String a("hello");
	String b("world");
	String c(a);
	a.print();
	c = b;
	c.print();
	
	system("pause");
	return 0;
}

之前复习C++的时候讲过了拷贝构造函数的写法,这里就不在叙述了,拷贝构造函数的知识在这一篇博客中拷贝构造函数的相关知识。这里主要讲赋值函数,也就是=号运算符重载。

我们在写=号运算符重载的时候,首先要判断这两个对象是不是同一个对象,如果是同一个对象就直接返回其本身,如果不是就得再判断被赋值的对象中是否有内存分配,如果有就得将其原本的内存释放掉,然后再为其分配一个能够容纳用于赋值的对象的内存空间

五、为什么C语言不支持函数重载而C++能支持

函数重载是用来描述同名函数具有相同或者相似的功能,但数据类型或者是参数不同的函数管理操作。

函数名经过C++编译器处理后包含了原函数名,函数参数数量及返回类型信息,但是C语言不会对函数名进行处理。

猜你喜欢

转载自blog.csdn.net/y____xiang/article/details/80258062