深入讲解引用、指针、值类型、引用类型的赋值(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。

 

  到此结束,通过以上六个案例,相信大家会对指针、引用、值类型、引用类型有更深的理解!

posted @ 2022-12-22 15:09  ShawBlack  阅读(434)  评论(0编辑  收藏  举报