C#CopyTo.docx

上传人:b****3 文档编号:4101081 上传时间:2023-05-06 格式:DOCX 页数:29 大小:34.05KB
下载 相关 举报
C#CopyTo.docx_第1页
第1页 / 共29页
C#CopyTo.docx_第2页
第2页 / 共29页
C#CopyTo.docx_第3页
第3页 / 共29页
C#CopyTo.docx_第4页
第4页 / 共29页
C#CopyTo.docx_第5页
第5页 / 共29页
C#CopyTo.docx_第6页
第6页 / 共29页
C#CopyTo.docx_第7页
第7页 / 共29页
C#CopyTo.docx_第8页
第8页 / 共29页
C#CopyTo.docx_第9页
第9页 / 共29页
C#CopyTo.docx_第10页
第10页 / 共29页
C#CopyTo.docx_第11页
第11页 / 共29页
C#CopyTo.docx_第12页
第12页 / 共29页
C#CopyTo.docx_第13页
第13页 / 共29页
C#CopyTo.docx_第14页
第14页 / 共29页
C#CopyTo.docx_第15页
第15页 / 共29页
C#CopyTo.docx_第16页
第16页 / 共29页
C#CopyTo.docx_第17页
第17页 / 共29页
C#CopyTo.docx_第18页
第18页 / 共29页
C#CopyTo.docx_第19页
第19页 / 共29页
C#CopyTo.docx_第20页
第20页 / 共29页
亲,该文档总共29页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

C#CopyTo.docx

《C#CopyTo.docx》由会员分享,可在线阅读,更多相关《C#CopyTo.docx(29页珍藏版)》请在冰点文库上搜索。

C#CopyTo.docx

C#CopyTo

1.CopyTo()和Clone()

相信大多数C#程序员都有查阅MSDN的好习惯,但是MSDN中提到这两个方法最大的区别就是:

一个方法创建了一个新Array对象,一个方法只是复制了Array引用.这句话本身没有错误,而且也正是他们的区别所在.只是这样会让人感到很迷惑.到底是什么区别呢?

这里还是先说说他们的共同点:

CopyTo()和Clone()都属于浅拷贝,这一点是毋庸置疑的.对于浅拷贝:

如果数组中的成员为值类型(如:

int,float,double,byte等),则完全复制数值到目标数组中,如果是引用类型(如用户自定义类型:

classStudent,classPeople,或者是类库中的类类型:

ArrayList等),则指复制引用给目标数组.

那么CopyTo()和Clone()方法的区别是什么呢?

其实他们的区别,也就是MSDN上说的最大的区别就是用法上的区别.我们可以在VS弹出智能提示的时候看看他们的返回值,CopyTo()的返回值是void,使用方法如下Array1.CopyTo(Array2,0);其中Array2必须是一个已经实例化的数组.而Clone()的返回值是object.使用方法如下Array2=Array1.Clone();其中Array2不必实例化.这样,我相信理解这两个方法的区别就很容易了.本质上并没有什么区别.都属于浅拷贝.如果拷贝所有的数组,就是用Clone().但是如果只是拷贝一部分,就可以选择CopyTo()了,CopyTo()的参数提示是这样的CopyTo(Arrayarray,intIndex).第二个参数index(索引)是指明从数组中的第几个对象开始复制.

2.浅拷贝和深拷贝的区别.

如上面所说的,浅拷贝对于值类型则复制值,对于引用类型则复制对象的引用(类似于指针).深拷贝则是完完全全的创建一个个新对象.对原来数组中的所有对象全部创建新对象.对新数组中的修改不会影响原来数组中的值或对象.但是如何实现深拷贝呢?

.NET库中似乎没有深拷贝的方法.这和实现深拷贝的原理有关系.若用户希望实现深拷贝.希望出现两个完全一样但又互不影响的数组.则必须自己写方法,对原数组中的每个对象实现拷贝,层层深入,直到这个对象中的对象中的对象……中的对象为值类型为止,因为只有值类型才是完全拷贝,对一个值进行修改不会影响另一个相同的值.这么说又有点难理解了.1.        深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。

举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。

比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。

考虑以下写法

      intsource=int.MaxValue;//

(1)初始化源对象为整数的最大值2,147,483,647

           intdest=source;//

(2)赋值,内部执行深拷贝

           dest=1024;//(3)对拷贝对象进行赋值

           source=2048;//(4)对源对象进行赋值

      首先

(2)中将source赋给dest,执行了深拷贝动作,其时dest和source的值是一样的,都是int.MaxValue;(3)对dest进行修改,dest值变为1024,由于是深拷贝,因此不会运行source,source仍然是int.MaxValue;(4)对source进行了修改,同样道理,dest仍然是1024,同时int.MaxValue的值也不变,仍然是2,147,483,647;只有source变成了2048。

      再考虑以下写法

       structPoint

       {

           publicintX;

           publicintY;

           publicPoint(intx,inty)

           {

               X=x;

               Y=y;

           }

       }

 

       Pointsource=newPoint(10,20);

       Pointdest=source;

 

       dest.X=20

    当dest.X属性变成20后,source的X属性仍然是10

2.        浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。

对其中任何一个对象的改动都会影响另外一个对象。

举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。

比较典型的就有Reference(引用)对象,如Class(类)。

考虑以下写法

       classPoint

       {

           publicintX;

           publicintY;

           publicPoint(intx,inty)

           {

               X=x;

               Y=y;

           }

       }

 

       Pointsource=newPoint(10,20);

       Pointdest=source;

  dest.X=20;

由于Point现在是引用对象,因此Pointdest=source的赋值动作实际上执行的是浅拷贝,最后的结果应该是source的X字段值也变成了20。

即它们引用了同一个对象,仅仅是变量明source和dest不同而已。

3.        引用对象的浅拷贝原理

引用对象之间的赋值之所以执行的是浅拷贝动作,与引用对象的特性有关,一个引用对象一般来说由两个部分组成

(1)一个具名的Handle,也就是我们所说的声明(如变量)

(2)一个内部(不具名)的对象,也就是具名Handle的内部对象。

它在MangedHeap(托管堆)中分配,一般由新增引用对象的New方法是进行创建

      如果这个内部对象已被创建,那么具名的Handle就指向这个内部对象在MangedHeap中的地址,否则就是null(从某个方面来讲,如果这个具名的handle可以被赋值为null,说明这是一个引用对象,当然不是绝对)。

两个引用对象如果进行赋值,它们仅仅是复制这个内部对象的地址,内部对象仍然是同一个,因此,源对象或拷贝对象的修改都会影响对方。

这也就是浅拷贝

4.        引用对象如何进行深拷贝

由于引用对象的赋值仅仅是复制具名Handle(变量)指向的地址,因此要对引用对象进行深拷贝就要重新创建一份该对象的实例,并对该对象的字段进行逐一赋值,如以下写法

       classPoint

       {

           publicintX;

           publicintY;

           publicPoint(intx,inty)

           {

               X=x;

               Y=y;

           }

       }

 

       Pointsource=newPoint(10,20);

       Pointdest=newPoint(source.X,source.Y);

       //或以下写法

       //Pointdest=newPoint()

       //dest.X=source.X

  //dest.Y=source.Y

      其时,source和dest就是两个互相独立的对象了,两者的修改都不会影响对方

 

5.一些需要注意的东西

      

(1):

String字符串对象是引用对象,但是很特殊,它表现的如值对象一样,即对它进行赋值,分割,合并,并不是对原有的字符串进行操作,而是返回一个新的字符串对象

      

(2):

Array数组对象是引用对象,在进行赋值的时候,实际上返回的是源对象的另一份引用而已;因此如果要对数组对象进行真正的复制(深拷贝),那么需要新建一份数组对象,然后将源数组的值逐一拷贝到目的对象中

3.C/C++中Static的作用详述

在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。

(1)先来介绍它的第一条也是最重要的一条:

隐藏。

当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。

为理解这句话,我举例来说明。

我们要同时编译两个源文件,一个是a.c,另一个是main.c。

下面是a.c的内容

chara='A';//globalvariable

voidmsg()

{

printf("Hello\n");

}

下面是main.c的内容

intmain(void)

{

externchara;//externvariablemustbedeclaredbeforeuse

printf("%c",a);

(void)msg();

return0;

}

程序的运行结果是:

AHello

你可能会问:

为什么在a.c中定义的全局变量a和函数msg能在main.c中使用?

前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。

此例中,a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。

如果加了static,就会对其它源文件隐藏。

例如在a和msg的定义前加上static,main.c就看不到它们了。

利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。

Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。

static定义的函数或变量是属于整个类的,不属于某个对象,调用是要用[类名]:

:

[函数名or变量名]

(2)static的第二个作用是保持变量内容的持久。

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

共有两种变量存储在静态存储区:

全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。

虽然这种用法不常见,但我还是举一个例子。

#include

intfun(void){

staticintcount=10;//事实上此赋值语句从来没有执行过

returncount--;

}

intcount=1;

intmain(void)

{

printf("global\t\tlocalstatic\n");

for(;count<=10;++count)

printf("%d\t\t%d\n",count,fun());

return0;

}

程序的运行结果是:

globallocalstatic

110

29

38

47

56

65

74

83

92

101

(3)static的第三个作用是默认初始化为0。

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。

在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。

不妨做个小实验验证一下。

#include

inta;

intmain(void)

{

inti;

staticcharstr[10];

printf("integer:

%d;string:

(begin)%s(end)",a,str);

return0;

}

程序的运行结果如下

integer:

0;string:

(begin)(end)

最后对static的三条作用做一句话总结。

首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。

 

4.switch中接受的合法参数有哪些类型

int

char

byte

short

long

enum

5.引用和指针

★相同点:

1.都是地址的概念;

指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。

★区别:

1.指针是一个实体,而引用仅是个别名;

2.引用使用时无需解引用(*),指针需要解引用;

3.引用只能在定义时被初始化一次,之后不可变;指针可变;

引用“从一而终”^_^

4.引用没有const,指针有const,const的指针不可变;

5.引用不能为空,指针可以为空;

6.“sizeof引用”得到的是所指向的变量(对象)的大小,而“sizeof指针”得到的是指针本身(所指向的变量或对象的地址)的大小;

typeid(T)==typeid(T&)恒为真,sizeof(T)==sizeof(T&)恒为真,

但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。

7.指针和引用的自增(++)运算意义不一样;

★联系

1.引用在语言内部用指针实现(如何实现?

)。

2.对一般应用而言,把引用理解为指针,不会犯严重语义错误。

引用是操作受限了的指针(仅容许取内容操作)。

 

6.memset,memcpy和strcpy的根本区别?

Memset

用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘’或‘\0’;

    

    例:

chara[100];memset(a,'\0',sizeof(a));

memset可以方便的清空一个结构类型的变量或数组,如:

structsample_struct

{

 char  csName[16];

 int   iSeq;

 int   iType;

};

对于变量

structsample_strcut stTest;

一般情况下,清空stTest的方法:

stTest.csName[0]='\0';

stTest.iSeq=0;

stTest.iType=0;

用memset就非常方便:

memset(&stTest,0,sizeof(structsample_struct));

如果是数组:

 structsample_struct  TEST[10];

memset(TEST,0,sizeof(structsample_struct)*10);

memcpy 

用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。

例:

chara[100],b[50];memcpy(b,a,sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。

Strcpy

就只能拷贝字符串了,它遇到'\0'就结束拷贝。

例:

chara[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。

str也可以用用个参数的strncpy(a,b,n)

========================================================

memset主要应用是初始化某个内存空间。

memcpy是用于copy源空间的数据到目的空间中。

strcpy用于字符串copy,遇到‘\0’,将结束。

如果你理解了这些,你应该知道他们的区别:

例如你初始化某块空间的时候,用到memcpy,那么应该怎么写,是不是显得很笨。

int m[100]

memset((void*)m,0x00,sizeof(int)*100); //=intm[100]={0};     //Ok!

memcpy((void*)m,"\0\0\0\0....",sizeof(int)*100);                  //it’swrong.

//注:

Win32编程:

ZeroMemory(buf,sizeof(buf))来清空内存更方便;

 

7.解释一下const

关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,现将本人的一些体会总结如下,期望对大家有所帮助:

一const基础

如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:

intb=500;

constint*a=&b;[1]

intconst*a=&b;[2]

int*consta=&b;[3]

constint*consta=&b;[4]

如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。

不知道,也没关系,我们可以参考《Effectivec++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a=3;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。

另外const的一些强大的功能在于它在函数声明中的应用。

在一个函数声明中,const可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。

有如下几种情况,以下会逐渐的说明用法:

A&operator=(constA&a);

voidfun0(constA*a);

voidfun1()const;//fun1()为类成员函数

constAfun2();

二const的初始化

先看一下const变量初始化的情况

1)非指针const常量初始化的情况:

Ab;

constAa=b;

2)指针(引用)const常量初始化的情况:

A*d=newA();

constA*c=d;

或者:

constA*c=newA();

引用:

Af;

constA&e=f;//这样作e只能访问声明为const的函数,而不能访问一般的成员函数;

[思考1]:

以下的这种赋值方法正确吗?

constA*c=newA();

A*e=c;

[思考2]:

以下的这种赋值方法正确吗?

A*constc=newA();

A*b=c;

三作为参数和返回值的const修饰符

其实,不论是参数还是返回值,道理都是一样的,参数传入时候和函数返回的时候,初始化const变量

1修饰参数的const,如voidfun0(constA*a);voidfun1(constA&a);

调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为constA*a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为constA&a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。

[注意]:

参数const通常用于参数为指针或引用的情况;

2修饰返回值的const,如constAfun2();constA*fun3();

这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。

constRationaloperator*(constRational&lhs,constRational&rhs)

{

returnRational(lhs.numerator()*rhs.numerator(),

lhs.denominator()*rhs.denominator());

}

返回值用const修饰可以防止允许这样的操作发生:

Rationala,b;

Radionalc;

(a*b)=c;

一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。

[总结]一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。

通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。

原因如下:

如果返回值为某个对象为const(constAtest=A实例)或某个对象的引用为const(constA&test=A实例),则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。

[思考3]:

这样定义赋值操作符重载函数可以吗?

constA&operator=(constA&a);

四类成员函数中const的使用

一般放在函数体后,形如:

voidfun()const;

如果一个成员函数的不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。

例如:

         constclassobj;

         obj.fun();                    //isok

如果没加const在fun()后面,则会出错!

五使用const的一些建议

1要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

2要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;

3在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

4const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

5不要轻易的将函数的返回值类型定为const;

6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

[思考题答案]

1这种方法不正确,因为声明指针的目的是为了对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确;

2这种方法正确,因为声明指针所指向的内容可变;

3这种做法不正确;

在co

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2