深入讲解引用、指针、值类型、引用类型的赋值(C++/C#混讲)
本文主要讲述的是值类型和引用类型的赋值
对值类型和引用类型的定义以及由来不清晰的可以看我之前的随笔,链接如下:
https://www.cnblogs.com/ShawBlack/p/16997772.html
由值类型和引用类型定义得知,值类型变量中存储的是其数据本身,而引用类型中存储的是数据的地址。
所以很明显
值类型的赋值,是一次深拷贝。
而引用类型的赋值,只是把地址赋值给新的引用类型变量而已,二者指向的是同一对象。若进行多次赋值,也仅仅只是多次地址的赋值而已。
举个栗子:
C#:
internal class Program { static void Main(string[] args) { WeatherForecast weatherForecast1 = new WeatherForecast() { TemperatureC = 111, Date = Convert.ToDateTime("1111.01.01") }; WeatherForecast weatherForecast2 = new WeatherForecast() { TemperatureC = 222, Date = Convert.ToDateTime("2222.02.02") }; // WeatherForecast weatherForecast_forCopy = weatherForecast1; //将weatherForecast1中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 weatherForecast_forCopy.Date = Convert.ToDateTime("3333.03.03"); weatherForecast_forCopy.TemperatureC = 333; Console.WriteLine("weatherForecast1.TemperatureC = " + weatherForecast1.TemperatureC); Console.WriteLine("weatherForecast1.Date = " + weatherForecast1.Date.ToLongDateString()); // weatherForecast_forCopy = weatherForecast2;//将weatherForecast2中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 weatherForecast_forCopy.Date = Convert.ToDateTime("4444.04.04"); weatherForecast_forCopy.TemperatureC = 444; Console.WriteLine("weatherForecast1.TemperatureC = " + weatherForecast1.TemperatureC); Console.WriteLine("weatherForecast1.Date = " + weatherForecast1.Date.ToLongDateString()); Console.WriteLine("weatherForecast2.TemperatureC = " + weatherForecast2.TemperatureC); Console.WriteLine("weatherForecast2.Date = " + weatherForecast2.Date.ToLongDateString()); } } public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } }
输出:
结果如大家所料,非常盒里!
C++:
<WeatherForecast.h>
#pragma once #include <string> #include<iostream> using namespace std; class WeatherForecast { public: int TemperatureC; };
<Program>
#include <iostream> #include <string> #include "WeatherForecast.h" int main() { WeatherForecast weatherForecast1; weatherForecast1.TemperatureC = 1111; WeatherForecast weatherForecast2 ; weatherForecast2.TemperatureC = 2222; // WeatherForecast weatherForecast_forCopy = weatherForecast1; //深拷贝 weatherForecast_forCopy.TemperatureC = 333; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; // weatherForecast_forCopy = weatherForecast2;//深拷贝 weatherForecast_forCopy.TemperatureC = 444; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast2.TemperatureC = " << weatherForecast2.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast2地址 = " << &weatherForecast2 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; return 0; }
输出:
结果就出乎意料了!不是说好只是复制地址吗,看着地址都不一样,肯定是每一次赋值都深拷贝了一份!
原因在此:C++中的数据默认都是值类型,若要变成引用类型,即在堆中申请空间存放该数据,则要添加关键词new
修正后的代码:
#include <iostream> #include <string> #include "WeatherForecast.h" int main() { WeatherForecast* weatherForecast1 = new WeatherForecast(); (*weatherForecast1).TemperatureC = 1111; //等于weatherForecast1->TemperatureC = 1111; WeatherForecast* weatherForecast2 = new WeatherForecast(); (*weatherForecast2).TemperatureC = 2222;//等于weatherForecast2->TemperatureC = 2222; // WeatherForecast* weatherForecast_forCopy = weatherForecast1; //将weatherForecast1中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 (*weatherForecast_forCopy).TemperatureC = 333; std::cout << "weatherForecast1.TemperatureC = " << (*weatherForecast1).TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << (*weatherForecast_forCopy).TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << weatherForecast1 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << weatherForecast_forCopy << std::endl; // weatherForecast_forCopy = weatherForecast2;//将weatherForecast2中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 (*weatherForecast_forCopy).TemperatureC = 444; std::cout << "weatherForecast1.TemperatureC = " << (*weatherForecast1).TemperatureC << std::endl; std::cout << "weatherForecast2.TemperatureC = " << (*weatherForecast2).TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << (*weatherForecast_forCopy).TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << weatherForecast1 << std::endl; std::cout << "weatherForecast2地址 = " << weatherForecast2 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << weatherForecast_forCopy << std::endl; return 0; }
输出:
Perfect!!!
另外再加一个无' new '关键字的指针应用,和上面一个例子的区别是,数据是否申请在堆中,以及是否需要手动释放内存的差别
代码如下:
#include <iostream> #include <string> #include "WeatherForecast.h" int main() { WeatherForecast weatherForecast1; weatherForecast1.TemperatureC = 1111; WeatherForecast weatherForecast2; weatherForecast2.TemperatureC = 2222; // WeatherForecast* weatherForecast_forCopy = &weatherForecast1; //将weatherForecast1中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 (*weatherForecast_forCopy).TemperatureC = 333; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << (*weatherForecast_forCopy).TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << weatherForecast_forCopy << std::endl; // weatherForecast_forCopy = &weatherForecast2;//将weatherForecast2中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 (*weatherForecast_forCopy).TemperatureC = 444; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast2.TemperatureC = " << weatherForecast2.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << (*weatherForecast_forCopy).TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast2地址 = " << &weatherForecast2 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << weatherForecast_forCopy << std::endl; return 0; }
输出:
再加一个指针解引用的栗子
指针通过' * 'address,进行解引用,获取指针地址对应的对象,这时的赋值操作是对该对象的深拷贝!!!而不是复制地址!!!
代码如下:
#include <iostream> #include <string> #include "WeatherForecast.h" int main() { WeatherForecast* weatherForecast1 = new WeatherForecast(); (*weatherForecast1).TemperatureC = 1111; //等于weatherForecast1->TemperatureC = 1111; WeatherForecast* weatherForecast2 = new WeatherForecast(); (*weatherForecast2).TemperatureC = 2222;//等于weatherForecast2->TemperatureC = 2222; // WeatherForecast weatherForecast_forCopy = *weatherForecast1; //将weatherForecast1中的地址解引用后深拷贝给weatherForecast_forCopy,二者指向的不是同一个对象 weatherForecast_forCopy.TemperatureC = 333; std::cout << "weatherForecast1.TemperatureC = " << (* weatherForecast1).TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << weatherForecast1 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; // weatherForecast_forCopy = *weatherForecast2; //将weatherForecast2中的地址解引用后深拷贝给weatherForecast_forCopy,二者指向的不是同一个对象 weatherForecast_forCopy.TemperatureC = 444; std::cout << "weatherForecast1.TemperatureC = " << (*weatherForecast1).TemperatureC << std::endl; std::cout << "weatherForecast2.TemperatureC = " << (*weatherForecast2).TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << weatherForecast1 << std::endl; std::cout << "weatherForecast2地址 = " << weatherForecast2 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; return 0; }
输出:
我们再最后讨论一个
在C++中有一个关键字非常容易和指针混淆,他就是' & '关键字,名曰' 引用 '。使用' & '创建数据的引用后,可以把其当做一个别名。其有两个特征,1.创建引用时必须为其初始化。2.仅在初始化赋值时,赋值地址,余下的赋值情况便皆为深拷贝。这两个特征,便是' 引用 '和' 指针 '的区别(指针可以在创建时不为其初始化,也可被多次赋值地址)
同样的栗子,代码如下:
#include <iostream> #include <string> #include "WeatherForecast.h" int main() { WeatherForecast weatherForecast1; weatherForecast1.TemperatureC = 1111; WeatherForecast weatherForecast2; weatherForecast2.TemperatureC = 2222; // WeatherForecast &weatherForecast_forCopy = weatherForecast1; //将weatherForecast1中的地址赋值给weatherForecast_forCopy,使得二者指向同一个对象 weatherForecast_forCopy.TemperatureC = 333; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; // weatherForecast_forCopy = weatherForecast2;//深拷贝 weatherForecast_forCopy.TemperatureC = 444; std::cout << "weatherForecast1.TemperatureC = " << weatherForecast1.TemperatureC << std::endl; std::cout << "weatherForecast2.TemperatureC = " << weatherForecast2.TemperatureC << std::endl; std::cout << "weatherForecast_forCopy.TemperatureC = " << weatherForecast_forCopy.TemperatureC << std::endl; std::cout << "weatherForecast1地址 = " << &weatherForecast1 << std::endl; std::cout << "weatherForecast2地址 = " << &weatherForecast2 << std::endl; std::cout << "weatherForecast_forCopy地址 = " << &weatherForecast_forCopy << std::endl; return 0; }
输出:
结果:你会发现,在weatherForecast_forCopy = weatherForecast2时,并没有再次赋值地址,而是将weatherForecast2的数据深拷贝给weatherForecast_forCopy。
到此结束,通过以上六个案例,相信大家会对指针、引用、值类型、引用类型有更深的理解!