我是靠谱客的博主 迷人星月,最近开发中收集的这篇文章主要介绍c++之拷贝构造的使用与nullptr和NULL的区别一: 拷贝构造的几种情况二:拷贝构造函数还在另二个方面使用三:nullptr与NULL与0的区别,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 一: 拷贝构造的几种情况
    • 1、 一个类中有成员对象
    • 2、继承类的拷贝构造
  • 二:拷贝构造函数还在另二个方面使用
  • 三:nullptr与NULL与0的区别

一: 拷贝构造的几种情况

1、 一个类中有成员对象

例如:

#include<iostream>
using namespace std;

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x){ cout << "value:" << this->value << endl; }
	~Object(){}
	Object(const Object& obj) :value(obj.value)
	 {
	  cout << "copy value:"<<this->value << endl; 
	 }
	Object& operator=(const Object& obj) 
	{
		if (this != &obj)
		{
			value = obj.value;
		}
		cout << this->value << endl;
		return *this;
	}
};

class Base
{
private:
	int num;
	Object obj;
public:
	Base(int x = 0) :num(x),obj(x) { cout <<"num:"<< this->num << endl; }
	~Base() {}
};

int main()
{
	Base base1(10);
	Base base2(base1);
}

在这里插入图片描述

①Base类中有成员对象obj,因此如果Object类中有的如拷贝构造,复制函数时,Base类中如果没有这些函数时,会默认创建相应的函数体。
②成员对象能够约束此类,而这个类不能够约束创建成员对象的类。

2、继承类的拷贝构造

示例:

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x) { cout << "value:" << this->value << endl; }
	~Object() {}
	Object(const Object& obj) :value(obj.value) { cout << "copy value:" << this->value << endl; }
	Object& operator=(const Object& obj)
	{
		if (this != &obj)
		{
			value = obj.value;
		}
		cout << "=" << this->value << endl;
		return *this;
	}
};

class Base:public Object
{
private:
	int num;
public:
	Base(int x = 0) :num(x), Object(x) { cout << "num:" << this->num << endl; }
	~Base() {}
};

int main()
{
	Base base1(10);
	Base base2(base1);
}

①当父类拷贝构造,赋值等函数时,子类没有这些函数时,而当子类要使用拷贝或赋值时,会默认合成这些函数

②当父类没有拷贝构造,赋值等函数时,子类有这些函数时,子类不能够约束父类去创建这些函数,而当子类要使用拷贝构造时,创建的隐藏父对象是调用父类的构造函数去创建。
③当父类和子类都没有拷贝构造,赋值等函数时,当子类要使用拷贝构造时,则是按位拷贝(地址)。

二:拷贝构造函数还在另二个方面使用

1 .当函数的形参是类的对象,调用函数时,进行形参与实参结合时使用。这时要在内存新建立一个局部对象,并把实参拷贝到新的对象空间中。

2.当函数的返回值是类对象,函数执行完成返回调用者时使用。理由也是要建立一个临时对象中,再返回调用者。因为局部对象在离开建立它的函数时就消亡了,不可能在返回调用函数后继续生存,所以在处理这种情况时,编译系统会在调用函数的表达式中创建一个无名临时对象,该临时对象的生存周期只在函数调用处的表达式中。所谓 return 对象,实际上是调用拷贝构造函数把该对象的值拷入临时对象空间。如果返回的是变量,处理过程类似,只是不调用构造函数。

3.拷贝构造函数的形参类型一定是引用类型,否则将引起无穷构造过程。

三:nullptr与NULL与0的区别

在C语言中我们将NULL用作空指针之用,NULL在C语言中的定义如下:

#define NULL    ((void *)0)

可以看到,C语言中NULL是一个void*指针,我们常用其来对指针变量进行初始化赋值或者作为返回类型为指针的函数的返回值(如函数执行失败时)等等。

所以说NULL实际上是一个空指针,如果在C语言中写入以下代码,编译是没有问题的,因为在C语言中把空指针赋给int和char指针的时候,发生了隐式类型转换,把void指针转换成了相应类型的指针。

int  *pi = NULL;
char *pc = NULL;

C++程序中的NULL

但是问题来了,以上代码如果使用C++编译器来编译则是会出错的,因为C++是强类型语言,void*是不能隐式转换成其他类型的指针的,所以实际上编译器提供的头文件做了相应的处理:

#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif

可见,在C++中,NULL实际上是0.因为C++中不能把void*类型的指针隐式转换成其他类型的指针,所以为了结果空指针的表示问题,C++引入了0来表示空指针,这样就有了上述代码中的NULL宏定义。
但是实际上,用NULL代替0表示空指针在函数重载时会出现问题,程序执行的结果会与我们的想法不同,举例如下:

#include <iostream>
using namespace std;
 
void func(void* i)
{
	cout << "func1" << endl;
}
 
void func(int i)
{
	cout << "func2" << endl;
}
 
void main(int argc,char* argv[])
{
	func(NULL);
	func(nullptr);
	getchar();
}
  

在这里插入图片描述
在这段代码中,我们对函数func进行可重载,参数分别是void*类型和int类型,但是运行结果却与我们使用NULL的初衷是相违背的,因为我们本来是想用NULL来代替空指针,但是在将NULL输入到函数中时,它却选择了int形参这个函数版本,所以是有问题的,这就是用NULL代替空指针在C++程序中的二义性。

nullptr的使用

nullptr关键字用于标识空指针,是std::nullptr_t类型的(constexpr)变量。它可以转换成任何指针类型和bool布尔类型(主要是为了兼容普通指针可以作为条件判断语句的写法),但是不能被转换为整数。

char *p1 = nullptr;     // 正确
int  *p2 = nullptr;     // 正确
bool b = nullptr;       // 正确. if(b)判断为false
int a = nullptr;        // 错误

注意nullptr和NULL以及0在作为条件判断时值都为false,它们两两之间进行等于(==)判断时值为true。

最后

以上就是迷人星月为你收集整理的c++之拷贝构造的使用与nullptr和NULL的区别一: 拷贝构造的几种情况二:拷贝构造函数还在另二个方面使用三:nullptr与NULL与0的区别的全部内容,希望文章能够帮你解决c++之拷贝构造的使用与nullptr和NULL的区别一: 拷贝构造的几种情况二:拷贝构造函数还在另二个方面使用三:nullptr与NULL与0的区别所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部