当前位置:文档之家› 浅析C#中的const与readonly异同+++

浅析C#中的const与readonly异同+++

C#引入了readonly修饰符来表示只读域,const来表示不变常量。顾名思义对只读域不能进行写操作,不变常量不能被修改,这两者到底有什么区别呢?只读域只能在初始化--声明初始化或构造器初始化--的过程中赋值,其他地方不能进行对只读域的赋值操作,否则编译器会报错。只读域可以是实例域也可以是静态域。只读域的类型可以是C#语言的任何类型。但const修饰的常量必须在声明的同时赋值,而且要求编译器能够在编译时期计算出这个确定的值。const修饰的常量为静态变量,不能够为对象所获取。const修饰的值的类型也有限制,它只能为下列类型之一(或能够转换为下列类型的):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, enum类型, 或引用类型。值得注意的是这里的引用类型,由于除去string类型外,所有的类型出去null值以外在编译时期都不能由编译器计算出他们的确切的值,所以我们能够声明为const的引用类型只能为string或值为null的其他引用类型。显然当我们声明一个null的常量时,我们已经失去了声明的意义--这也可以说是C#设计的尴尬之处!

这就是说,当我们需要一个const的常量时,但它的类型又限制了它不能在编译时期被计算出确定的值来,我们可采取将之声明为static readonly来解决。但两者之间还是有一点细微的差别的。看下面的两个不同的文件:

//file1.cs

//csc /t:library file1.cs

using System;

namespace MyNamespace1

{

public class MyClass1

{

public static readonly int myField = 10;

}

}

//file2.cs

//csc /r:file1.dll file2.cs

using System;

namespace MyNamespace2

{

public class MyClass1

{

public static void Main()

{

Console.WriteLine(MyNamespace1.MyClass1.myField);

}

}

}

我们的两个类分属于两个文件file1.cs 和file2.cs,并分开编译。在文件file1.cs内的域myField声明为static readonly时,如果我们由于某种需要改变了myField的值为20,我们只需重新编译文件file1.cs为file1.dll,在执行file2.exe时我们会得到20。但如果我们将static readonly改变为const后,再改变myField的初始化值时,我们必须重新编译所有引用到file1.dll的文件,否则我们引用的MyNamespace1.MyClass1.myField将不会如我们所愿而改变。这在大的系统开发过程中尤其需要注意。实际上,如果我们能够理解const 修饰的常量是在编译时便被计算出确定的值,并代换到引用该常量的每一个地方,而readonly时在运行时才确定的量--只是在初始化后我们不希望它的值再改变,我们便能理解C#设计者们的良苦用心,我们才能彻底把握const和readonly的行为!

---------------------

Features:

readonly和const都是用来标识常量的[1]。

const可用于修饰class的field或者一个局部变量(local variable);而readonly仅仅用于修饰class的field。

const常量的值必定在编译时就已明确并且恒定的;而readonly常量却有一点不同,那就是其值可以在运行时编译,当然,它也必须遵守作为常量的约束,那就是值必须恒定不变。

const常量必须在声明的同时对其进行赋值,并且确保该值在编译时可确定并恒定;而readonly常量则可以根据情况选择在声明的同时对其赋予一个编译时确定并恒定的值,或者将其值的初始化工作交给实例构造函数(instant constructor)完成。如:public readonly string m_Now = DateTime.Now.ToString();,m_Now会随着运行时实际情况变化而变化。

const常量属于类级别(class level)而不是实例对象级别(instant object level),并且它不能跟static结合一起使用,该常量的值将由整个类的所有实例对象共同分享(详细论述参见后面的Remark区域)。

readonly常量既可以是类级别也可以是实例对象级别的,这取决于它的声明以及初始化工作怎么实施。readonly可以与static结合使用,用于指定该常量属于类级别,并且把初始化工作交由静态构造函数(static constructor)完成(有关如何把readonly常量声明为类级别或实例对象级别的论述清参见后面的Remark区域)。

能被const修饰声明为常量的类型必须是以下的基元类型(primitive type):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, float, bool, decimal, string。

object, 数组(Array)和结构(struct)不能被声明为const常量。

一般情况下,引用类型是不能被声明为const常量的,不过有一个例外:string。该引用类型const常量的值可以有两种情况,string或null。其实,string虽然是引用类型,但是.NET却对它特别处理,这种处理叫做字符串恒定性(immutable),使得string的值具有只读特性。有关字符串恒定性的内容,可以参考《Microsoft .NET框架程序设计(修订版)》。

Examples:

using System;

public class Order

{

public Order()

{

Guid guid = Guid.NewGuid();

ID = guid.ToString("D");

}

// 对于每一份订单,其订单序号都是实时确定的常量。

public readonly string ID;

public override string ToString()

{

return "Order ID: " + ID;

}

}

Explaintion:

如果结合数据库使用,ID field通常都会都会与某个表的主健(primary key)关联起来,如Orders表的OrderID。数据库的主健通常采用以下三种方式:

自动递增值。你可以通过把DataColumn.AutoIncrement设定为true值来激活自动递增特性。

唯一名称。这个是使用自己定义的算法来生成一个唯一序列号。

GUID(全局唯一标识符)。你可以通过System.Guid结构来生成GUID,如上例。

using System;

class Customer

{

public Customer(string name, int kind)

{

m_Name = name;

m_Kind = kind;

}

public const int NORMAL = 0;

public const int VIP = 1;

public const int SUPER_VIP = 2;

private string m_Name;

public string Name

{

get { return m_Name; }

}

private readonly int m_Kind;

public int Kind

{

get { return m_Kind; }

}

public override string ToString()

{

if(m_Kind == SUPER_VIP)

return "Name: " + m_Name + "[SuperVip]";

else if(m_Kind == VIP)

return "Name: " + m_Name + "[Vip]";

else

return "Name: " + m_Name + "[Normal]";

}

}

Remarks:

一般情况下,如果你需要声明的常量是普遍公认的并作为单个使用,例如圆周率,黄金分割比例等。你可以考虑使用const常量,如:public const double PI = 3.1415926;。如果你需要声明常量,不过这个常量会随着实际的运行情况而决定,那么,readonly常量将会是一个不错的选择,例如上面第一个例子的订单号Order.ID。

另外,如果要表示对象内部的默认值的话,而这类值通常是常量性质的,那么也可以考虑const。更多时候我们对源代码进行重构时(使用Replace Magic Number with Symbolic Constant),要去除魔数(Magic Number)的影响都会借助于const的这种特性。

对于readonly和const所修饰的变量究竟是属于类级别的还是实例对象级别的问题,我们先看看如下代码:

使用Visual C#在Main()里面使用IntelliSence插入Constant的相关field的时候,发现ReadonlyInt 和 InstantReadonlyInt需要指定Constant的实例对象;而ConstInt和StaticReadonlyInt却要指定Constant class(参见上面代码)。可见,用const或者static readonly修饰的常量是属于类级别的;而readonly修饰的,无论是直接通过赋值来初始化或者在实例构造函数里初始化,都属于实例对象级别。一般情况下,如果你需要表达一组相关的编译时确定常量,你可以考虑使用枚举类型(enum),而不是把多个const常量直接嵌入到class中作为 field,不过这两种方式没有绝对的孰优孰劣之分。

using System;

enum CustomerKind

{

SuperVip,

Vip,

Normal

}

class Customer

{

public Customer(string name, CustomerKind kind)

{

m_Name = name;

m_Kind = kind;

}

private string m_Name;

public string Name

{

get { return m_Name; }

}

private CustomerKind m_Kind;

public CustomerKind Kind

{

get { return m_Kind; }

}

public override string ToString()

{

return "Name: " + m_Name + "[" + m_Kind.ToString() + "]";

}

}

然而,当这种结合使用枚举和条件判断的代码阻碍了你进行更灵活的扩展,并有可能导致日后的维护成本增加,你可以代之以多态,使用Replace Conditional with Polymorphism来对代码进行重构。(有关多态的详细介绍,请参见《今天你多态了吗?》一文。)

Comments:

readonly field准确来说应该翻译成为“只读域”,这里是为了统一翻译用语才将它和const两者所修饰的量都说成“常量”,希望没有引起误会。

------------------------------------------------

C# FAQ: const和static readonly有什么区别?

我们都知道,const和static readonly的确很像:通过类名而不是对象名进行访问,在程序中只读等等。在多数情况下可以混用。

二者本质的区别在于,const的值是在编译期间确定的,因此只能在声明时通过常量表达式指定其值。而static readonly是在运行时计算出其值的,所以还可以通过静态构造函数来赋值。

明白了这个本质区别,我们就不难看出下面的语句中static readonly和const能否互换了:

1. static readonly MyClass myins = new MyClass();

2. static readonly MyClass myins = null;

3. static readonly A = B * 20;

static readonly B = 10;

4. static readonly int [] constIntArray = new int[] {1, 2, 3};

5. void SomeFunction()

{

const int a = 10;

...

}

1:不可以换成const。new操作符是需要执行构造函数的,所以无法在编译期间确定

2:可以换成const。我们也看到,Reference类型的常量(除了String)只能是Null。

3:可以换成const。我们可以在编译期间很明确的说,A等于200。

4:不可以换成const。道理和1是一样的,虽然看起来1,2,3的数组的确就是一个常量。

5:不可以换成readonly,readonly只能用来修饰类的field,不能修饰局部变量,也不能修饰property 等其他类成员。

因此,对于那些本质上应该是常量,但是却无法使用const来声明的地方,可以使用static readonly。例如C#规范中给出的例子:

public class Color

{

public static readonly Color Black = new Color(0, 0, 0);

public static readonly Color White = new Color(255, 255, 255);

public static readonly Color Red = new Color(255, 0, 0);

public static readonly Color Green = new Color(0, 255, 0);

public static readonly Color Blue = new Color(0, 0, 255);static readonly需要注意的一个问题是,对于一个static readonly的Reference类型,只是被限定不能进行赋值(写)操作而已。而对其成员的读写仍然是不受限制的。

public static readonly MyClass myins = new MyClass();

myins.SomeProperty = 10; //正常

myins = new MyClass(); //出错,该对象是只读的

但是,如果上例中的MyClass不是一个class而是一个struct,那么后面的两个语句就都会出错。

private byte red, green, blue;

public Color(byte r, byte g, byte b)

{

red = r;

green = g;

blue = b;

}

}

using System;

namespace ConstantLab

{

class Program

{

static void Main(string[] args)

{

Constant c = new Constant(3);

Console.WriteLine("ConstInt = " + Constant.ConstInt.ToString());

Console.WriteLine("ReadonlyInt = " + c.ReadonlyInt.ToString());

Console.WriteLine("InstantReadonlyInt = " +

c.InstantReadonlyInt.ToString());

Console.WriteLine("StaticReadonlyInt = " +

Constant.StaticReadonlyInt.ToString());

Console.WriteLine("Press any key to continue");

Console.ReadLine();

}

}

class Constant

{

public Constant(int instantReadonlyInt)

{

InstantReadonlyInt = instantReadonlyInt;

}

public const int ConstInt = 0;

public readonly int ReadonlyInt = 1;

public readonly int InstantReadonlyInt;

public static readonly int StaticReadonlyInt = 4;

}

}

const int

const int* a = &b 和const* int a = &b的区别收藏 如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况: int b = 500; const int* a = &b; [1] int const *a = &b; [2] int* const a = &b; [3] const int* const a = &b; [4] 如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法: A& operator=(const A& a); void fun0(const A* a ); void fun1( ) const; // fun1( ) 为类成员函数 const A fun2( ); --------------------------------------------------------------------------------------------------------------------------------------------- const int * pi 、int const * pi与int * const pi及其操作 (本贴已经做了重大修改) 1 从const int i 说起

const的常用用法大总结

本文档含有三部分 第一部分 const的用法,特别是用在函数后面(第1-4页) 第二部分 C++的那点事,const,指针和引用的混合使用(第5-9页) 第三部分 const 总结(第10-13页) const的用法,特别是用在函数后面 在普通的非const成员函数中,this的类型是一个指向类类型的const指针(第 4.2.5 节)。可以改变this所指向的值,但不能改变this所保存的地址。在const成员函数中,this的类型是一个指向const类类型对象的const指针。既不能改变this所指向的对象,也不能改变this所保存的地址。 关键字:Const,Const函数,Const变量,函数后面的Const 看到const 关键字,C++程序员首先想到的可能是const 常量。这可不是良好的条件反射。如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体。 const 是constant 的缩写,“恒定不变”的意思。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多C++程序设计书籍建议:“Use const whenever you need”。 1.用const 修饰函数的参数 如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数: 如果输入参数采用“指针传递”,那么加const 修饰可以防止意外地改动该指针,起到保护作用。 例如StringCopy 函数: void StringCopy(char *strDestination, const char *strSource); 其中strSource 是输入参数,strDestination 是输出参数。给strSource 加上const修饰后,如果函数体内的语句试图改动strSource 的内容,编译器将指出错误。 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。 例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用户自定义的数据类型。 对于非内部数据类型的参数而言,象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A 类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。 为了提高效率,可以将函数声明改为void Func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数void Func(A &a) 存在一个缺点: “引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。

const,static,extern用法总结

--------------------------CONST--------------------------------------- const应用: 一、对于基本声明 const int r=100;//标准const变量声明加初始化,编译器经过类型检查后直接用100在编译时替换。 二、对于指针 1. int x=10; const int *r=&x; //指针指向的内容是常量,r指向的内容不能够通过r改变,但如果是非const,内容可以通过自己改变,而且r指针可以改变,可以指向其它的整形. //*r=*r+1;NO //x++;YES //r=&y;YES 2. int const *r=&x; 与1完全相同 3. int * const r=&x; //指针指向是常量,不能修改去指向其它内容,但指向的内容可以修改 //r=&y;NO //*r=*r+1;YES //x++;YES 4.const int * const r=&x; //综合1、3用法,r是一个指向常量的常量型指针,指针指向不能改变,指针内容不能改变,内容可以自身改变 //r=&y;NO //*r=*r+1;NO //x++;YES 三、对于类型检查 可以把非const对象赋予const指针,这样就不能改变.但是不能把const赋给非const,除非先强制转换 const int x=100; int *p=(int*)&x; *p++; 四、对于函数 1.void Fuction1(const int r); //此处为参数传递const值,意义是变量初值不能被函数改变 2.const int Fuction1 (int); //此处返回const值,意思指返回的原函数里的变量的初值不能被修改,但是函数按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何的const或非const类型变量,完全不需要加上这个const关键字。 3.Class CX; //内部有构造函数,声明如CX(int r =0) CX Fuction1 () { return CX(); } const CX Fuction2 () { return CX(); } Fuction1() = CX(1); //没有问题,可以作为左值调用 Fuction2() = CX(1); //编译错误,const返回值禁止作为左值调用。 4.函数中指针的const传递和返回: int F1 (const char *pstr); //作为传递的时候使用const修饰可以保证不会通过这个指针来修改传递参数的初值 const char *F2();//意义是函数返回的指针指向的对象是一个const对象,它必须赋给一个同样是指向const对象的指针 const char * const F3(); //比上面多了一个const,这个const的意义只是在他被用作左值时有效,它表明了这个指针除了指向const对象外,它本身也不能被修改,所以就不能当作左值来处理。 五、对于类 1.首先,对于const的成员变量,只能在构造函数里使用初始化成员列表来初始化,试图在构造函数体内进行初始化const成员变量会引起编译错误。初始化成员列表形如:X:: X ( int ir ): r(ir) {} //假设r是类X的const成员变量 注意:类的构造和析构函数都不能是const函数。 2.建立了一个const成员函数,但仍然想用这个函数改变对象内部的数据。(函数不能修改类的数据成员)

.net高级工程师面试题

.net软件工程师面试题 基础题: 1.简述string[]、ArrayList、List的区别。 数组: 优点: o数组在内存中是连续存储的,索引速度非常快; o赋值和修改元素也很简单; 不足: o两个数据之间插入数据比较麻烦; o声明数组的时候,必须指明数组的长度,数组长度过长会造成内存浪费,数组的长度过短,会造成数据溢出错误。 ArrayList: 优点: https://www.doczj.com/doc/9f3944263.html, framework 提供的用于数据存储和检索的专用类 o大小依据存储的数据来动态扩展和收缩 o继承IList,可以方便的进行数据的添加、插入和删除 缺点: o允许插入不同类型的数据,都当做object类型处理 o数据处理时可能出现类型不匹配的错误

o存在装箱(值=》引用)拆箱的操作,会带来很大的性能损耗 List: 优点: o声明List集合时,需要声明集合内数据的对象类型 o避免了类型安全问题和装箱拆箱的性能问题 2.简述装箱和拆箱操作中的性能损耗是如何产生的。 3.简述对https://www.doczj.com/doc/9f3944263.html,中的事件机制的理解。 4.在一个https://www.doczj.com/doc/9f3944263.html,的三层结构系统中,以登录操作为例,简述在各层中如何组织代码。 5.简述相比DATASET,实体类在WEB项目中的优点与缺点。 6.简述GC是如何工作的。 Java采用VM(Virtual Machine)机制,由VM来管理程序的运行当然也包括对GC管理。90年代末期.NET出现了,.NET采用了和Java类似的方法由CLR(Common Language Runtime)来管理。 Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root 为基础,遍历应用程序在Heap上动态分配的所有对象[2],通过识别它们是否被引用来确定哪些对象是已经死亡的、哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。为了实现这个原理,GC有多种算法。比较常见的算法有Reference Counting,Mark Sweep,Copy Collection等等。目前主流的虚拟系统.NET CLR,Java VM和Rotor都是采用的Mark Sweep算法。

C++中const用法详解

const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。类型声明中const用来修饰一个常量,有如下两种写法,那么,请问,下面分别用const限定不可变的内容是什么? 1)、const在前面 const int nValue;//nValue是const const char *pContent; //*pContent是const, pContent可变 const (char *) pContent;//pContent是const,*pContent可变 char* const pContent; //pContent是const,*pContent可变 const char* const pContent; //pContent和*pContent都是const 2)、const在后面,与上面的声明对等 int const nValue;// nValue是const char const * pContent;// *pContent是const, pContent可变 (char *) const pContent;//pContent是const,*pContent可变 char* const pContent;// pContent是const,*pContent可变 char const* const pContent;// pContent和*pContent都是const 答案与分析: const和指针一起使用是C语言中一个很常见的困惑之处,在实际开发中,特别是在看别人代码的时候,常常会因为这样而不好判断作者的意图,下面讲一下我的判断原则:当const所在代码段中不包含括号时,沿着*号划一条线,如果const 位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。你可以根据这个规则来看上面声明的实际意义,相信定会一目了然。

const和readonly区别

我们都知道,const和static readonly的确很像:通过类名而不是对象名进行访问,在程序中只读等等。在多数情况下可以混用。二者本质的区别在于,const的值是在编译期间确定的,因此只能在声明时通过常量表达式指定其值。而static readonly是在运行时计算出其值的,所以还可以通过静态构造函数来赋值。明白了这个本质区别,我们就不难看出下面的语句中static readonly和const能否互换了: 1. static readonly MyClass myins = new MyClass(); 2. static readonly MyClass myins = null; 3. static readonly B = 10; static readonly A = B * 20; 4. static readonly int [] constIntArray = new int[] {1, 2, 3}; 5. void SomeFunction() { const int a = 10; ... } 6.private static string astr="abcd"; private const string str = astr+"efg"; 1:不可以换成const。new操作符是需要执行构造函数的,所以无法在编译期间确定 2:可以换成const。我们也看到,Reference类型的常量(除了String)只能是Null。 3:可以换成const。我们可以在编译期间很明确的说,A等于200。 4:不可以换成const。道理和1是一样的,虽然看起来1,2,3的数组的确就是一个常量。5:不可以换成readonly,readonly只能用来修饰类的field,不能修饰局部变量,也不能修饰property等其他类成员。 6.错误:如果在astr前加上const或者const改为readonly即可; 总结:1.const、readonly和static readonly定义的常量,指定初始值后(包括在构造函数内指定的初始值) 将不可更改,可读不可写; 2.const定义时必须指定初始值,而readonly定义时可以不进行初始化(MS建议在定义时初始值),同时也可以在构造函数内指定初始值, 并以构造函数内指定的值为准; 3.const和static readonly定义的常量是静态的,只能由类直接访问;而readonly定义的常量是非静态的,只能由实例对象访问; 4.static readonly常量,如果在构造函数内指定初始值,则必须是静态无参构造函数; 5.const是编译时常量,readonly是运行时常量;cosnt较高效,readonly较灵活。在应用上以static readonly代替const,以平衡const在灵活性上的不足, 同时克服编译器优化cosnt性能,所带来的程序集引用不一致问题; 文章2:

C基础知识25个常见问题

C# 基础知识 25个常见问题(1) 2007-04-12 16:53 当初学 C# 时是找个人大概问了一下数据类型和分支语句就开始做项目了。这两天又全面的看了一下相关的基础知识(学而时习之嘛),总结了25个问题: 1.静态变量和非静态变量的区别? 2.const 和 static readonly 区别? 3.extern 是什么意思? 4.abstract 是什么意思? 5.internal 修饰符起什么作用? 6.sealed 修饰符是干什么的? 7.override 和 overload 的区别? 8.什么是索引指示器? 9.new 修饰符是起什么作用? 10.this 关键字的含义? 11.可以使用抽象函数重写基类中的虚函数吗? 12.密封类可以有虚函数吗? 13.如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有 get 和 set 两个呢? 14.abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗? 15.接口可以包含哪些成员? 16.类和结构的区别? 17.接口的多继承会带来哪些问题? 18.抽象类和接口的区别? 19.别名指示符是什么? 20.如何释放非托管资源? 21.P/Invoke是什么? 22.StringBuilder 和 String 的区别? 23.explicit 和 implicit 的含义? 24.params 有什么用? 25.什么是反射? 以下是我做的一份参考答案(C# 语言范畴之内),如果有不准确、不全面的,欢迎各位朋友指正! 1.静态变量和非静态变量的区别? 答:静态变量: 静态变量使用 static 修饰符进行声明 在所属类被装载时创建 通过类进行访问

const变量使用总结

或许还有不少人对于const修饰符理解的并不深刻,都只是停留在一个比较浅的层面上,仅仅是在读别人代码的时候看到了const修饰符的使用,自己的写代码的过中从未使用过,所以自然对于const修饰符比较陌生。那么到底什么是const 修饰符,我们在自己编写C语言代码的过程中又该如何有效的使用const修饰符呢,现在让我们来学习下const修饰符的使用。 const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,即就是说其所修饰的对象为常量。当你代码中想要设法阻止一个变量被改变,那么这个时候可以选择使用const关键字。在你给一个变量加上const修饰符的同时,通常需要对它进行初始化,在之后的程序中就不能再去改变它。 可能有的人会有一个疑问,我们不是有在C中有预处理指令#define VariableNameVariableValue可以很方便地进行值替代,干嘛还要引入const修饰符呢?!这是因为预处理语句虽然可以很方便的进行值得替代,但它有个比较致命的缺点,即预处理语句仅仅只是简单值替代,缺乏类型的检测机制。这样预处理语句就不能享受C编译器严格类型检查的好处,正是由于这样,使得它的使用存在着一系列的隐患和局限性。 在讲解const修饰符之前,我们在此首先给出const修饰符的几个典型作用: 1. const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令 2. 可以保护被修饰的东西,防止意外的修改,增强程序的健壮性; 3. 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4. 可以节省空间,避免不必要的内存分配。 接下来看看具体的使用。 一、const修饰符在函数体内修饰局部变量。 constint n=5; 和 intconst n=5;

C++ const 精髓

1.const的用法: 看到const 关键字,C++程序员首先想到的可能是const 常量。这可不是良好的条件反射。如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体。 const 是constant 的缩写,“恒定不变”的意思。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多C++程序设计书籍建议:“Use const whenever you need”。 1.用const 修饰函数的参数 如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数: 如果输入参数采用“指针传递”,那么加const 修饰可以防止意外地改动该指针,起到保护作用。 例如StringCopy 函数: void StringCopy(char *strDestination, const char *strSource); 其中strSource 是输入参数,strDestination 是输出参数。给strSource 加上const修饰后,如果函数体内的语句试图改动strSource 的内容,编译器将指出错误。 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。 例如不要将函数void Func1(int x) 写成void Func1(const int x)。 同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用户自定义的数据类型。 对于非内部数据类型的参数而言,象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A 类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。 为了提高效率,可以将函数声明改为void Func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数void Func(A & a) 存在一个缺点: “引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。 以此类推,是否应将void Func(int x) 改写为void Func(const int &x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。 问题是如此的缠绵,我只好将“const &”修饰输入参数的用法总结一下。 对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。例如将void Func(A a) 改为void Func(const A &a)。 对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。

C++中const和template的用法

1、C中的CONST CONST const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。另外CONST在其他编程语言中也有出现,如C++、PHP5、C#.net、HC08 C。 C中CONST的使用: 虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题。 问题:const变量 & 常量 为什么下面的例子在使用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢? const int n = 5; int a[n]; 答案与分析: 1)、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的,例如5, "abc",等,肯定是只读的,因为常量是被编译器放在内存中的只读区域,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符(Qualifier)。上述代码中变量n被修饰为只读变量,可惜再怎么修饰也不是常量。而ANSI C规定数组定义时长度必须是“常量”,“只读变量”也是不可以的。 2)、注意:在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而const int n,n只是一个变量(常量 != 不可变的变量,但在标准C++中,这样定义的是一个常量,这种写法是对的),实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C对数组的规定限制了它。 3)、那么,在ANSI C 语言中用什么来定义常量呢?答案是enum类型和#define宏,这两个都可以用来定义常量。 问题:const变量 & const 限定的内容 下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢? typedef char * pStr; char string[4] = "abc"; const char *p1 = string;

const的所有用法——Dan+Saks

In my last column, I discussed one of the reasons why the rules by which a compiler can place data into ROM are a bit more complicated in C++ than they are in C.1I have more to say about that subject, but before I do, I’d like to reply to the following query I received through e-mail from Phil Baurer at Komatsu Mining Systems: “We’re having an interesting prob-lem using const with a typedef. I hoped you could comment on this sit-uation. I am wondering if we are bumping into some unknown (by us) rule of the C language. “We are using the Hitachi C com-piler for the Hitachi SH-2 32-bit RISC microcontroller. We thought the fol-lowing code: t y p e d e f v o i d*V P; c o ns t V P v e c t o r T a b l e[] ={....};(1) should be identical to: c o ns t v o i d*v e c t o r T a b l e[] ={....};(2)“However, the linker places v e c t o r T a b l e in (1) into the C O N S T A N T section, but it places v e c t o r T a b l e in (2) into the D A T A section. “Is this the proper behavior or a bug in the compiler?” This is proper behavior; it is not a bug. You are indeed bumping into some rules of the C language that you apparently don’t know about. Don’t feel bad; you’re not alone. I believe many other C and C++ pro- grammers are confused about these rules, which is why I’m answering this in my column. I presented some of these rules in an earlier column.2However, in look- ing back at that column, I don’t think I emphasized strongly enough the points which seem to be the source of your confusion. So let me try again. Declarat ors Here’s the first insight: Every declaration in C and C++ has two principal parts: a sequence of zero or more declaration specifiers, and a sequence of one or more declarators, separated by commas. For example: A declarator is the name being declared, possibly surrounded by operators such as *, [], (), and (in the case of C++) &. As you already know, the symbol *in a declarator means “pointer to” and []means “array of.” Thus, *x[N]is a declarator indicating that x is an “array of N elements of pointer to ...” something, where that something is the type specified in the declaration specifiers. For example, s t a t i c u ns i g ne d l o ng i nt*x[N]; declares x as an object of type “array of N elements of pointer to unsigned long int.” (As explained later, the key- word s t a t i c does not contribute to the type.) How did I know that *x[N]is an “array of ... pointer to ...” rather than a “pointer to an array of ...?” It follows from this rule: The operators in a declarator group accord- ing to the same precedence as they do when they appear in an expression. For example, if you check the near- est precedence chart for either C or C++, you’ll see that []has higher precedence than *. Thus the declara- tor *x[N]means that x is an array before it’s a pointer. Parentheses serve two roles in declarators: first, as the function call operator, and second, as grouping. As the function call operator, ()have the same precedence as []. As grouping, ()have the highest precedence of all. Embedded Systems Programming FEBRUARY 1999 13 Dan Saks const T vs.T const Although C and C++ read mostly from top-to- bottom and left-to-right, pointer declarations read, in a sense, backwards.

200多个C#面试题含答案

一.选择,填空题 1.在https://www.doczj.com/doc/9f3944263.html,中,对于Command对象的ExecuteNonQuery()方法和ExecuteReader()方法, 下面叙述错误的是(C)。 a)insert、update、delete等操作的Sql语句主要用ExecuteNonQuery()方法来执行; b)ExecuteNonQuery()方法返回执行Sql语句所影响的行数。 c)Select操作的Sql语句只能由ExecuteReader()方法来执行;~ d)ExecuteReader()方法返回一个DataReder对象; 2.面向对象的语言具有__继承性_性、_封装性_性、_多态性性。 3.能用foreach遍历访问的对象需要实现________________接口或声明 ________________方法的类型。(@) 答:IEnumerable 、 GetEnumerator() 4.在C#中,表示一个字符串的变量应使用以下哪条语句定义?( B ) A. CString str; B. string str; C. Dim str as string D. char * str; 5.在C#编制的财务程序中,需要创建一个存储流动资金金额的临时变量,则应使用下列哪 条语句?( A ) A. decimal theMoney; B. int theMoney; C. string theMoney; D. Dim theMoney as double 6.C#中,新建一字符串变量str,并将字符串”Tom's Living Room”保存到串中,则应该 使用下列哪条语句?(B) A. string str = “Tom\'s Living Room”; B. string str = “Tom's Living Room”; C. string str(“Tom's Living Room”); D. string str(“Tom”s Living Room”); 7.应用https://www.doczj.com/doc/9f3944263.html, 访问数据时,Connection 对象的连接字符串中Initial Catalog 子串的含义是 ( A ) A. Connection 对象连接到的数据库的名称 B. Connection 对象的身份验证信息 C. Connection 对象的最大连接时间 D. Connection 对象使用的缓存大小 8.使用Visual Studio .NET 的”新建C# 项目”创建一个名为”SimpleForm”的Windows 表单应用程序,则在生成_______文件中可设置该程序集的Copyright、Trademark 等属 性信息.( D )

const的使用方法

const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable)。 1、函数体内修饰局部变量。 例: void func(){ const int a=0; } 首先,我们先把const这个单词忽略不看,那么a是一个int类型的局部自动变量,我们给它赋予初始值0。 然后再看const. const作为一个类型限定词,和int有相同的地位。 const int a; int const a; 是等价的。于是此处我们一定要清晰的明白,const修饰的对象是谁,是a,和int没有关系。const 要求他所修饰的对象为常量,不可被改变,不可被赋值,不可作为左值(l-value)。 这样的写法也是错误的。 const int a; a=0; 这是一个很常见的使用方式: const double pi=3.14; 在程序的后面如果企图对pi再次赋值或者修改就会出错。 然后看一个稍微复杂的例子。 const int* p; 还是先去掉const 修饰符号。 注意,下面两个是等价的。 int* p; int *p; 其实我们想要说的是,*p是int类型。那么显然,p就是指向int的指针。 同理 const int* p; 其实等价于

const int (*p); int const (*p); 即,*p是常量。也就是说,p指向的数据是常量。 于是 p+=8; //合法 *p=3; //非法,p指向的数据是常量。 那么如何声明一个自身是常量指针呢?方法是让const尽可能的靠近p; int* const p; const右面只有p,显然,它修饰的是p,说明p不可被更改。然后把const去掉,可以看出p是一个指向int形式变量的指针。 于是 p+=8; //非法 *p=3; //合法 再看一个更复杂的例子,它是上面二者的综合 const int* const p; 说明p自己是常量,且p指向的变量也是常量。 于是 p+=8; //非法 *p=3; //非法 const 还有一个作用就是用于修饰常量静态字符串。 例如: const char* name="David"; 如果没有const,我们可能会在后面有意无意的写name[4]='x'这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了const,这个错误就 能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译 期被发现。 const 还可以用来修饰数组 const char s[]="David"; 与上面有类似的作用。 2、在函数声明时修饰参数 来看实际中的一个例子。 NAME

C#题1

(1)下列关于C#语言特点的描述正确的有哪些(BD)? A C#继承于C/C++,所以C#的功能要比前两者强大。 B C#语言的跨平台性是基于.NET平台的 C C#语言对面向对象机制的支持要比C++全面 D C#语言能更好地与XML融合 (2)下列说法中不正确的是(D)? A C#中以“;”作为一条语句的结束 B C#中注视是不参与编译的 C C#有三种不同的注释类型 D swith语言中case标签结束可是有跳转语句,也可以没有。 (3)下列哪些标识符是合法的(ADE)? AStudent B3_A C new D@public E_age (4)下列关于变量的说法中正确的是(ABC) AC#中变量可以划分为值类型和引用类型 B在同一行中可以申请多个变量 C可以在定义变量的同时为其赋值 D变量是用来存放数据值的 (5)下列哪些是C#的引用类型(ABD)? A类类型B接口类型C结构类型D字符串类型(6)判断下列语句中哪个存在语法错误(B)。 bool a=true bool b=false bool c=true int i=0 A if(a||b) B if(i) C if(i!=3) D if((i==3)==false) (7)下列关于switch语句的表述中哪些是错误的(ACD)? Aswitch语句的控制表达式可以是任何数据类型 B switch语句可以出现default标签,也可以不出现default标签 C switch中可以有两个或两个以上的case标签的常量与控制表达式的值相同 D switch语句中case标签结束可以有跳转语句,也可以没有。 (8)下列关于异常处理的表述中哪些是正确的(D)? A try、catch、finally三个字句必须同时出现,才能正确处理异常 B catch字句能且只能出现一次 C try字句中所抛出的异常一定能被catch字句捕获 D无论异常是否抛出,finally子句中的内容都会被执行。 (9)下面程序的执行结果为(D) Class MainClass {Public static void Main(string[]args) {int x=10; int temp=0; for(int i=0;i

CONST181使用说明书(2010.01.22)_

一总述 我们的压力专家在三十多年研制和生产活塞压力计的基础上,利用国外新技术、新材料使我公司研制、生产出的压力校验器能更好地满足用户校验压力仪器、仪表时使用。因此,便携、省力、使用方便、密封性能好和易维护正是我公司压力校验器的特点。我公司还参与起草了机械部标准:JB/T599《压力表校验器》。我公司的多项专利技术均处于国际先进水平。 压力校验器是压力校验系统的重要组成设备,密封性是压力校验器的最重要指标。经过与国外同类产品比较,本公司的压力校验器在密封性、造压的轻便性和微量调节性能等方面处于同类产品的领先地位。本公司的压力校验器特别考虑了微压受温度影响问题,高压压力校验器针对高压被检压力仪表回检时不能平稳降压的问题,我们做出了很好的解决方案。 压力校验器的研制,参照了有关标准,如机械部标准:JB/T599《压力表校验器》、JB/T 7393-1994《活塞式压力计》及国家标准:GB/T 14211-93《机械密封试验方法》,并且参考了有关国家计量检定规程:JJG 129-90《一等标准活塞式压力计检定规程》、JJG 49-1999《弹簧管式精密压力表及真空表检定规程》、JJG 52-1999《弹簧管式一般压力表、压力真空表及真空表检定规程》。

我公司的液体压力泵的密封性优于国家标准五倍以上。本公司的气体压力泵的密封性优于国家标准十倍以上。 活塞与压力校验器组成压力测试系统,是动态平衡系统。在活塞有效行程内,系统压力不变,现象是压力稳定。数字压力校验仪与压力校验器组成的压力测试系统是密闭非动态平衡系统。加压过程中,由于压缩原因,分子需吸收能量,分子间隙缓慢减小,所以压力不会立即稳定(表现为压力下降、系统不稳),需等待一段时间压力才会稳定。降压过程中,由于膨胀原因,分子需释放能量,分子间隙增大,所以压力不会立即稳定(表现压力上升、系统不稳),需等待一段时间压力才会稳定。 上述二种现象,只是物理过程不同,该现象在液体压力校验器与数字压力校验仪组成的系统中表现尤其明显。 本公司压力校验器的研制充分考虑了国内被检压力仪表的实际状况,压力校验器具有防尘、过滤功能,维护极其方便。 国家标准对密封性试验的主要要求:压力校验器在加压10分钟后开始计时,5分钟内压力校验器的泄漏量不得超过满量程的5%。 国家检定规程对密封性试验的主要要求:压力校验器在加压5分钟后开始计时,5分钟内压力校验器的泄漏量不得超过满量程的4%。

相关主题
文本预览
相关文档 最新文档