C#与C++参数传递方式对比.

  这几天在看C++标准,其中看到C++引用,用于函数传递参数要比之前传递指针安全,方便.所以想到把C#里相关概念拿来比较下.

  如下是在C#的测试代码:

    public class Book
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

    public struct StructBook
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

    class Program
    {
        static void testValue(StructBook book)
        {
            book.Id = 1;
            book.Name = "n1";
        }

        static void testPtr(Book book)
        {
            book.Id = 2;
            book.Name = "n2";
            book = new Book();
            book.Id = 3;
            book.Name = "n3";
        }

        static void testRef(ref StructBook book)
        {
            book.Id = 4;
            book.Name = "n4";
            //book = new StructBook();
            //book.Id = 5;
            //book.Name = "n5";
            var xx = new StructBook();
            xx.Id = 5;
            xx.Name = "n5";
            book = xx;
        }

        static void testPtrRef(ref Book book)
        {
            book.Id = 6;
            book.Name = "n6";
            book = new Book();
            book.Id = 7;
            book.Name = "n7";
        }

        static void Main(string[] args)
        {
            StructBook sutbook = new StructBook();
            sutbook.Id = 0;
            sutbook.Name = "n0";

            Console.WriteLine("----value:");
            testValue(sutbook);
            Console.WriteLine(sutbook.Id);
            Console.WriteLine(sutbook.Name);

            Book book = new Book();
            book.Id = sutbook.Id;
            book.Name = sutbook.Name;
            Console.WriteLine("----reference value:");
            testPtr(book);
            Console.WriteLine(book.Id);
            Console.WriteLine(book.Name);

            sutbook.Id = book.Id;
            sutbook.Name = book.Name;
            Console.WriteLine("----value reference:");
            testRef(ref sutbook);
            Console.WriteLine(sutbook.Id);
            Console.WriteLine(sutbook.Name);

            book.Id = sutbook.Id;
            book.Name = sutbook.Name;
            Console.WriteLine("----reference reference:");
            testPtrRef(ref book);
            Console.WriteLine(book.Id);
            Console.WriteLine(book.Name);

            Console.Read();
        }
    }

参数传递

  上面主要演示C#中值传递与引用传递二种类型(值类型与引用类型)的不同.先看一下运行结果.

  结果没什么好说的,差不多是被大家讲烂了的.简单来说,C#里默认全是值传递,值传递就是在函数内生成一份临时变量,对临时变量的修改不会影响本身.不同的值类型传递的是本身,而引用类型传递的是他引用.对应的结果就是上面的testPtr与testRef.一种是值类型,修改的是临时变量,在函数调用外是不变的.另外是引用类型,如果是修改引用里的值,这是可以的,而如果修改的是引用本身(这个是值传递的临时变量),就是testPtr里的book = new Book();这个是修改是影响不到函数外部的.

  至于testRef与testPtrRef,都属性引用传递,那么他传递的就是他本身,在函数内的修改都会直接修改他本身,都会影响函数外面.

  我们对应上面几个函数,在C++中,也增加相应的一些方法,大家可以看到一些相同与不同之处.

using namespace std;

class Book
{

public:
    string name;
    int id;

    Book()
    {
        cout << "Create new Book: " << this << endl;
    }

    ~Book()
    {
        cout << "Delete Book in: " << this << endl;
    }

    //void operator = (const Book& book)
    //{

    //}

    string(iName)()
    {
        return name;
    }
};
void testValue(Book book)
{
    cout << "temp address:" << &book << endl;
    book.id = 1;
    book.name = "n1";
}

void testPtr(Book* book)
{
    book->id = 2;
    book->name = "n2";
    cout << "old address:" << book << endl;
    book = new Book();
    cout << "new address:" << book << endl;
    book->id = 3;
    book->name = "n3";
    delete book;
}

void testRef(Book& book)
{
    book.id = 4;
    book.name = "n4";
    cout << "old address:" << &book << endl;
    auto xx = Book();
    xx.id = 5;
    xx.name = "n5";
    //这句话会调用 = 操作符.并没有发生地址操作.
    //所以后面的删除的临时变量不会对book本身有影响
    book = xx;
    cout << "new address:" << &book << endl;

    //内存分配的位置不管是在堆还上栈上不影响结果
    //auto nb = new Book();
    //nb->id = 55;
    //nb->name = "n55";
    //cout << "old value:" << &book << endl;
    //book = *nb;
    //cout << "new value:" << &book << endl;
    //delete nb;
}

void testPtrRef(Book*& book)
{
    book->id = 6;
    book->name = "n6";
    auto xx = new Book();
    xx->id = 7;
    xx->name = "n7";

    cout << "old address:" << book << endl;
    delete book;
    book = xx;
    cout << "new address:" << book << endl;
}

void test19()
{
    auto xb = new Book();
    xb->id = 0;
    xb->name = "n0";

    cout << "----value:" << endl;
    testValue(*xb);
    cout << xb->id << endl;
    cout << xb->name << endl;

    cout << "----pointer value:" << endl;
    testPtr(xb);
    cout << xb->id << endl;
    cout << xb->name << endl;

    cout << "----reference value:" << endl;
    testRef(*xb);
    cout << xb->id << endl;
    cout << xb->name << endl;

    cout << "----pointer reference:" << endl;
    testPtrRef(xb);
    cout << xb->id << endl;
    cout << xb->name << endl;

    delete xb;
}

C++ 函数传递

  

  我们可以看到与C#中相似的结果.在C++中,主要是值传递,指针传递,引用传递.指针传递也可以归到值传递中,因为指针传递的指针也是要生成临时指针.就表现的现象来说,C++中的值传递和C#的值传递值类型比较相似,C++中的指针传递和C#中的值传递引用类型比较相似,C++中的指针引用传递和C#的引用传递(包含值类型与引用类型)比较相似.

  C#中,结构是值类型,类是引用类型,而C++中,结构与类可以说没有区别,所以上面比对中,C++的传递方式要对比C#的传递方式在类型方式,还有上面比对中,我没说C++的引用传递和C#的什么比较像,只说C++中的指针引用传递和C#的引用传递比较像.那么C++的单独引用传递和C#的有那些不同.

  C++中,testValue里我们可以看到,book的地址变了,说明和C#一样,book是临时变量,在testValue完成后,直接调用析构函数删除临时变量.

  在testPtr中,我们可以看到book在new后,book是指向了新的地址,但是在外部调用显示book时,还是前面2与n2,这里delete book有和没有,结果是一样的,只是会有内存泄漏.这个的表现和C#值传递引用类型一样,在重新new后,对book所做的更改都无效,因为指针传递说到底还是值传递,传递的是地址,就是说,这个在testPtr会重新生成一份,但是他的指向与原变量一样.所以前面针对id与name的设置都会更新到函数外部,但是这个临时变量重新new后,他就已经和main里的book所指向的位置不一样,在家可以对比看下输出.我们通过这个也能更容易理解C#值传递引用类型内部发生的情况.

  而在C++的testRef中,虽然结果和C#的testRef一样,但是又可以说完全不是一回事.在C++,引用有比较严格的规定,比如引用初始化后,就不能再修改引用指向的对象.可以看输出结果里的地址的对比.而C#中的引用传递的值是可以重新修改指向的对象.具体可看传递引用类型参数(C# 编程指南).C++的引用像是* const,或是说加强限定的指针与一些语法糖的组合.至于结果显示是n5与5,主要是默认的赋值操作引起的,我们可以在Book类里重新定义赋值操作,什么都不做,就可以看到结果是4与n4了.

  在testPtrRef,我们传递指针的引用过去,通过输出结果上的地址显示,我们可以看到我们在函数内重新指向新的位置,改动能带到函数外.当然指针的指针也能做到这个效果.就和前面说的一样,引用应是一种特殊的指针表示方式,引用能做的到,指针也能做到,反之就不一定了.同时我们也可以猜测C#中,引用类型当值传递时,相当于默认加上指针,而用引用传递时,相当于有个二级指针.  

  下面是原来看过几道测试题,最后一个如何具体化?

//float(*(*f)(float, float))(float);
void test7()
{
    float(**a)[10];//float 数组 指针 指针
    float(*aa)[10]; //float 数组 指针
    float aaa[10];
    aa = &aaa;
    a = &aa;
    aaa[0] = 4;
    cout << ***a << endl;

    float*(*b)[10];//float* 数组 指针
    float* bb[10];//指针数组
    bb[0] = new float[2];
    b = &bb;
    bb[0][0] = 5;
    cout << ***b << endl;

    float(*c[10])();
    c[0] = [](){return 6.0f; };
    cout << (**c)() << endl;

    float*((*d)[10]);//float* 数组 指针
    float*(dd[10]);
    dd[0] = new float(7);
    d = &dd;
    dd[0][0] = 7.0f;
    cout << ***d << endl;

    float(*e)();
    e = [](){ return 8.0f; };
    cout << e() << endl;

    //如何具体化.
    float(*(*f)(float, float))(float);
    auto ff = fvv;
}

时间: 2024-10-26 12:01:04

C#与C++参数传递方式对比.的相关文章

Java和C参数传递方式的比较

java中的形参是复制实参的一份拷贝(对于引用类型则是复制引用的拷贝,在栈中的拷贝),所以在函数中改变形参是无法改变实参的值的,改变引用只是将形参所代表的引用指向另外的新的对象,而实参的引用还指向原来的对象,改变形参引用的成员当然会影响实参引用成员的值,因为他们的引用都指向同一个对象.[Java只有值传递Java只有值传递Java只有值传递,重要的事情说3遍] 示例代码: public class ExchangeValue { public static void main(String[]

【整理】--C++三种参数传递方式

在C++中,共有三种参数传递方式: 按值传递(pass by value) 地址传递(pass by pointer) 引用传递(pass by reference) (1)按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用.这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”. 使用这种方式,调用函数本

Java函数参数传递方式详解

在阅读本文之前,根据自己的经验和理解,大家可以先思考并选择一下Java函数的参数传递方式: A. 是按值传递的? B. 按引用传递的? C. 部分按值部分按引用? 此处暂不宣布正确答案,我们通过一个简单的例子让大家自己找答案: 1. 先定义一个类型Value Java代码   public static class Value { private String value = "value"; public String getValue() { return value; } pub

C语言函数参数传递方式

C语言中函数的参数传递方式有两种:传值.传地址. 1.传值调用 在被调用函数中开辟出一个临时的内存空间,在主调用函数进入被调用函数前,会将实参进行拷贝,拷贝的数据放在该临时内存空间中,供被调用函数使用.当被调用函数返回时,该临时内存空间即被释放. 1 #include<stdio.h> 2 3 int test_func(char *q) 4 { 5 long lAddr=&q; // 被调用时,光标选中“&q”,显示结果(随机)为:0x002df7ac {0x013058b8

java中参数传递方式话题终结实例

java新手入门面临的一个经典的话题,本文意在终结这个话题,java中有说法:Java里面参数传递都是按值传递,怎么理解这句话?用文字说明恐怕不容易说明白,说明白恐怕也难以想明白. 前提 先明确一下,按值还是按引用的概念,它是来自c++语言,引用不是汉语词典中的一个词,而是c++的概念--"&"这个符号还记得吧? 为什么有这个话题呢?其一,是对按引用传递理解不透彻:其二,诸多java书籍及讨论论点并没有切中要害.?? 一句话概括,按值传参还是按引用传参,既然是参数传递方式,那么

C# 同一应用程序域不同线程之间的参数传递方式

很久没有写博客了,最近的项目不用写代码.今天没事就看看thread之间的参数传递方式,这里主要适用于运行在不同线程的两个方法之间参数传递.直接看代码 1.方法之间直接传递参数 void DemoParam() { Console.WriteLine("DemoParam:" + Thread.CurrentThread.ManagedThreadId); //Thread t = new Thread(new ParameterizedThreadStart(testparam));

产品经理学Python:参数传递方式

这是关于Python的第5篇文章,主要介绍下参数传递方式和如何设计自己的函数. (一) 本篇主要介绍2种参数传递方式. 位置参数 调用函数时,根据函数定义的参数位置来传递参数. 1 def right_triangle_area(a,b): 2 return 1/2*a*b 3 4 print(right_triangle_area(3,4)) 5 # 位置参数传递 求直角三角形面积,a.b分别为两条直角边,这里调用函数时使用的是位置参数传递.在位置参数传递中,参数的顺序是不可改变的. 关键词参

基于.Net Framework 4.0 Web API开发(2):ASP.NET Web APIs 参数传递方式详解

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.调用API过程中参数的传递是必须的,本节就来谈谈API使用过程中参数的传递方式. 各种参数传递方式的实现: ASP.NET Web API参数有两种传递方式,一种是请求时携带QueryString,对应API 开发中的FromUrlAttribute属性,也是参数传递默认属性,并且每个API可以含有多个此类型的参数,主要应对GET请求,但此种方式

函数参数传递方式详解

1. 函数参数传递方式之一:值传递 (1)值传递的一个错误认识 先看如下的一个问题: void Exchg1(int x, int y) /* 定义中的x,y变量被称为Exchg1函数的形式参数 */ { int tmp; tmp = x; x= y; y= tmp; printf("x = %d, y = %d.\n", x, y); } 问:你认为这个函数是在做什么呀? 答:好像是对参数x.y的值对调吧? 请往下看,我想利用这个函数来完成对a,b两个变量值的对调,程序如下: mai