- 慧慧
-
const 放在函数后表示这个函数是常成员函数, 常成员函数是不能改变成员变量值的函数。
const 限定符,它把一个对象转换成一个常量。
举例:
为了使成员函数的意义更加清楚,我们可在不改变对象的成员函数的函数原型中加上const说明:
class Point
{
public:
int GetX() const;
int GetY() const;
void SetPt (int, int);
void OffsetPt (int, int);
private:
int xVal, yVal;
};
const成员函数应该在函数原型说明和函数定义中都增加const限定:
int Point::GetY() const
{
return yVal;
}
class Set {
public:
Set (void){ card = 0; }
bool Member(const int) const;
void AddElem(const int);
};
bool Set::Member (const int elem) const
{
}
非常量成员函数不能被常量成员对象调用,因为它可能企图修改常量的数据成员:
const Set s;
s.AddElem(10); // 非法: AddElem不是常量成员函数
s.Member(10); // 正确
函数在数学上的定义:给定一个非空的数集A,对A施加对应法则f,记作f(A),得到另一数集B,也就是B=f(A).那么这个关系式就叫函数关系式,简称函数。
- clou
-
这样的函数叫常成员函数。常成员函数可以理解为是一个“只读”函数,它既不能更改数据成员的值,也不能调用那些能引起数据成员值变化的成员函数,只能调用const成员函数。
const是什么意思?
约束啊。。。2023-07-21 22:40:416
const是什么意思
const是C++中的CONST函数,作用为把一个对象转换成一个常量。const的用法:1、常变量变量用const修饰,其值不得被改变。任何改变此变量的代码都会产生编译错误。Const加在数据类型前后均可。2、常指针const跟指针一起使用的时候有两种方法。const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。3、Const和成员函数声明成员函数时,末尾加const修饰,表示在成员函数内不得改变该对象的任何数据。这种模式常被用来表示对象数据只读的访问模式。4、Const和引用用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。Const加在数据类型前后均可。c语言程序设计的基础内容:《C语言程序设计》是软件工程专业学生必修的专业基础课程,是后续C++语言程序设计、数据结构、操作系统等课程的先修课程。C语言是一门面向过程的计算机编程语言。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。本课程的主要内容包括数据类型、数据运算、语句、函数、程序结构、数组、结构体、指针和文件。设置本课程的主要目的是培养学生的程序设计、实现及调试能力。通过本课程的学习,使学生学会用计算机处理问题的思维方法,增强解决问题的编程实践能力,为将来从事软件开发及后继课程的学习和解决工程问题、科学技术问题奠定基础。2023-07-21 22:40:541
const在c++中的作用
const用于定义常量。const用于限定指针或限定指向的内容。const在类定义中的使用。const类型常量名=常量;(1)常量一经定义就不能修改,例如:constinti=5;//定义常量i,i=10;//错误,修改常量,i++;//错误,修改常量。(2)const常量必须在定义时初始化,例如:constintn;//错误,常量n未被初始化。(1)指向常量的指针:所指内容为常量,指针为变量(const放在内容类型前)例如:constchar*p=“good”;//const在char之前,表示指针指向的字符为常量,*(p+2)=‘l";//错误,所指对象为常量,p=“very”;//正确,指针为变量(2)指针常量:指针为常量,指向内容为变量(const放在指针前)例如:char*constp=“good”;//指针名前加const,表示指针本身是常量,p=“very”;//错误,*(p+2)=‘l";//正确。(3)指向常量的常量指针:指针为常量,指向内容也为常量(const加到内容类型前,也放到指针前),例如:constchar*constp=“good”;//const指针前(指针为常量),//const加到内容类型前(内容为常量),p=“very”;//错误,指针为常量,*(p+2)=‘l";//错误,内容为常理。2023-07-21 22:42:121
C++中const什么意思?
const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令 1)修饰一般常量,常数组,常对象 修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; int const a[5]={1, 2, 3, 4, 5}; 或 const int a[5]={1, 2, 3, 4, 5}; class A; const A a; 或 A const a; (2)修饰指针 const int *A; 或 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A; //指针A和A指向的对象都不可变 (3)修饰引用 const double & v; 该引用所引用的对象不能被更新 (4)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (5)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; }; 这样,在调用函数Fun时就不能修改类里面的数据 (6)在另一连接文件中引用const常量 extern const int i; //正确的引用 extern const int j=10; //错误!常量不可以被再次赋值2023-07-21 22:42:2210
C语言中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都是const2023-07-21 22:43:223
C++在函数声明时,后面跟个const是什么意思?
常量不能被修改2023-07-21 22:43:576
VB中const用法
const是定义常数,例如:const pi =3.14159,那么你在代码中输入pi就相当于输入3.14159。就是用一个类似变量的东西代替数值提高可读性,但要注意,它不是变量。SPIF_UPDATEINIFILE并不是VB里面的常数,要使用的话必须定义常数。VC有微软提供的支持库,所以可以直接使用。2023-07-21 22:44:461
c++中const的作用
1.const 修饰类的成员变量,表示成员常量,不能被修改。2.const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。3.如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数。4.const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。5.类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符6.const在*的左边,则指针指向的变量的值,不可直接通过指针改变(可以通过其他途径改变); 在*的右边,则指针的指向不可变。简记为“左定值,右定向”。2023-07-21 22:45:311
VB中const是什么意思?
用法和dim相似,dim用来定义变量而const用来定义常量visual basic中使用关键字const来声明符号常量,声明格式为:const 符号常量名 AS类型=表达式说明:(1)符号常量的命名规则符号常量的命名规则与标识符的命名规则相同,为了便于与般变量名互相区别,符号常量一般用大写字母表示。(2) As 类型该选项说明符号常量的数据类型。若省略,数据类型由表达式的值的类型决定。也可以在符号常量名后加类型说明符进行说明。(3)表达式表达式是由数值常量、字符串常量以及运算符组成的,但是表式中不能出现变量和函数2023-07-21 22:45:396
const的几种使用方法
(1)const定义常量:const dataType constData=value;//const修饰的类型为dataType的变量value不可变.(2)指针中使用const,主要有三种方式a.指针本身是常量,它本身不可变char* const ptr;b.指针所指向的内容是常量,指向的内容不可变const char* ptr;c.两者都不可变const char* const ptr; (3)函数中使用consta.传指针参数前添加constvoid* A(const char* Str); //Str指向的内容被修饰为常量b.传引用参数前添加constvoid* A(const ClassType &obj); //obj在函数体内被修饰为常量(4)类中使用consta.使用const修饰成员变量使用const修饰类的成员函数,表示成员常量,它只能在初始化列表中赋值。如:class A{A(int x): val(x) { } ; //在初始化列表中定义const int val; //成员常量}b.使用const修饰类的成员函数,如 int getNum(int a)const;这样当程序修改了类的数据成员或调用了非const成员函数时,编译器就会报错。c.使用const修饰类的对象,或者类对象引用或指针这对象中的所有数据成员都不能被修改,对于对象指针或对象引用也一样。在这种情况下,同时不能通过对象名调用对象中的非const成员,这符合安全规则。2023-07-21 22:46:061
什么是const
const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。2023-07-21 22:46:271
c++中const的作用是什么?
const关键字至少有下列n个作用: (1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了; (2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const; (3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值; (4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量; (5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。例如:const classA operator*(const classA& a1,const classA& a2); operator*的返回结果必须是一个const对象。如果不是,这样的变态代码也不会编译出错:classA a, b, c;(a * b) = c; // 对a*b的结果赋值 操作(a * b) = c显然不符合编程者的初衷,也没有任何意义。2023-07-21 22:46:351
Java的const怎么用
如果定义常量用final2023-07-21 22:46:453
C语言中const有什么用途
(1)可以定义 const 常量 (2)const 可以修饰函数的参数、返回值.详细内容: 1、什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 2、为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 3、cons有什么主要的作用? (1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4、如何使用const? (1)修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; (2)修饰常数组 定义或说明一个常数组可采用如下格式: int const a[5]={1, 2, 3, 4, 5}; const int a[5]={1, 2, 3, 4, 5}; (3)修饰常对象 常对象是指对象常量,定义格式如下: class A; const A a; A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 (4)修饰常指针 const int *A; //const修饰指向的对象,A可变,A指向的对象不可变 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A;//指针A和A指向的对象都不可变 (5)修饰常引用 使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下: const double & v; (6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下: void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。 (7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; ..... }; 这样,在调用函数Fun时就不能修改类里面的数据 (9)在另一连接文件中引用const常量 extern const int i;//正确的引用 extern const int j=10;//错误!常量不可以被再次赋值 另外,还要注意,常量必须初始化! 例如: const int i=5; 5、几点值得讨论的地方: (1)const究竟意味着什么? 说了这么多,你认为const意味着什么?一种修饰符?接口抽象?一种新类型? 也许都是,在Stroustup最初引入这个关键字时,只是为对象放入ROM做出了一种可能,对于const对象,C++既允许对其进行静态初始化,也允许对他进行动态初始化。理想的const对象应该在其构造函数完成之前都是可写的,在析够函数执行开始后也都是可写的,换句话说,const对象具有从构造函数完成到析够函数执行之前的不变性,如果违反了这条规则,结果都是未定义的!虽然我们把const放入ROM中,但这并不能够保证const的任何形式的堕落,我们后面会给出具体的办法。无论const对象被放入ROM中,还是通过存储保护机制加以保护,都只能保证,对于用户而言这个对象没有改变。换句话说,废料收集器(我们以后会详细讨论,这就一笔带过)或数据库系统对一个const的修改怎没有任何问题。 (2)位元const V.S. 抽象const? 对于关键字const的解释有好几种方式,最常见的就是位元const 和 抽象const。下面我们看一个例子: class A { public: ...... A f(const A& a); ...... }; 如果采用抽象const进行解释,那就是f函数不会去改变所引用对象的抽象值,如果采用位元const进行解释,那就成了f函数不会去改变所引用对象的任何位元。 我们可以看到位元解释正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。 为什么这样呢?因为使用位元const有2个好处: 最大的好处是可以很容易地检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就可以了。另外,如果我们采用了位元const,那么,对于一些比较简单的const对象,我们就可以把它安全的放入ROM中,对于一些程序而言,这无疑是一个很重要的优化方式。(关于优化处理,我们到时候专门进行讨论) 当然,位元const也有缺点,要不然,抽象const也就没有产生的必要了。 首先,位元const的抽象性比抽象const的级别更低!实际上,大家都知道,一个库接口的抽象性级别越低,使用这个库就越困难。 其次,使用位元const的库接口会暴露库的一些实现细节,而这往往会带来一些负面效应。所以,在库接口和程序实现细节上,我们都应该采用抽象const。 有时,我们可能希望对const做出一些其它的解释,那么,就要注意了,目前,大多数对const的解释都是类型不安全的,这里我们就不举例子了,你可以自己考虑一下,总之,我们尽量避免对const的重新解释。 (3)放在类内部的常量有什么限制? 看看下面这个例子: class A { private: const int c3 = 7; // ??? static int c4 = 7; // ??? static const float c5 = 7; // ??? ...... }; 你认为上面的3句对吗?呵呵,都不对!使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式初始化的整型或枚举类型,而且必须是static和const形式。这显然是一个很严重的限制! 那么,我们的标准委员会为什么做这样的规定呢?一般来说,类在一个头文件中被声明,而头文件被包含到许多互相调用的单元去。但是,为了避免复杂的编译器规则,C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话,这种规则就被破坏了。 (4)如何初始化类内部的常量? 一种方法就是static 和 const 并用,在内部初始化,如上面的例子; 另一个很常见的方法就是初始化列表: class A { public: A(int i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,例如: class A { public: A() {} private: static const int i;//注意必须是静态的! }; const int A::i=3; (5)常量与数组的组合有什么特殊吗? 我们给出下面的代码: const int size[3]={10,20,50}; int array[size[2]]; 有什么问题吗?对了,编译通不过!为什么呢? Const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了:) 你再看看下面的例子: class A { public: A(int i=0):test[2]({1,2}) {}//你认为行吗? private: const int test[2]; }; vc6下编译通不过,为什么呢? 关于这个问题,前些时间,njboy问我是怎么回事?我反问他:“你认为呢?”他想了想,给出了一下解释,大家可以看看:我们知道编译器堆初始化列表的操作是在构造函数之内,显式调用可用代码之前,初始化的次序依据数据声明的次序。初始化时机应该没有什么问题,那么就只有是编译器对数组做了什么手脚!其实做什么手脚,我也不知道,我只好对他进行猜测:编译器搜索到test发现是一个非静态的数组,于是,为他分配内存空间,这里需要注意了,它应该是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],这就导致数组的初始化实际上是赋值!然而,常量不允许赋值,所以无法通过。 呵呵,看了这一段冠冕堂皇的话,真让我笑死了!njboy别怪我揭你短呀:)我对此的解释是这样的:C++标准有一个规定,不允许无序对象在类内部初始化,数组显然是一个无序的,所以这样的初始化是错误的!对于他,只能在类的外部进行初始化,如果想让它通过,只需要声明为静态的,然后初始化。 这里我们看到,常量与数组的组合没有什么特殊!一切都是数组惹的祸! (6)this指针是不是const类型的? this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。 (7)const到底是不是一个重载的参考对象? 先看一下下面的例子: class A { ...... void f(int i) {......}//一个函数 void f(int i) const {......}//上一个函数的重载 ...... }; 上面是重载是没有问题的了,那么下面的呢? class A { ...... void f(int i) {......}//一个函数 void f(const int i) {......}//????? ...... }; 这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子: class A { ...... void f(int& ) {......}//一个函数 void f(const int& ) {......}//????? ...... }; 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 (8)什么情况下为const分配内存? 以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。 A、作为非静态的类成员时; B、用于集合时; C、被取地址时; D、在main函数体内部通过函数来获得值时; E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。 F、当const的长度比计算机字长还长时; G、参数中的const; H、使用了extern时。 不知道还有没有其他情况,欢迎高手指点:) (9)临时变量到底是不是常量? 很多情况下,编译器必须建立临时对象。像其他任何对象一样,它们需要存储空间而且必须被构造和删除。区别是我们从来看不到编译器负责决定它们的去留以及它们存在的细节。对于C++标准草案而言:临时对象自动地成为常量。因为我们通常接触不到临时对象,不能使用与之相关的信息,所以告诉临时对象做一些改变有可能会出错。当然,这与编译器有关,例如:vc6、vc7都对此作了扩展,所以,用临时对象做左值,编译器并没有报错。 (10)与static搭配会不会有问题? 假设有一个类: class A { public: ...... static void f() const { ......} ...... }; 我们发现编译器会报错,因为在这种情况下static不能够与const共存! 为什么呢?因为static没有this指针,但是const修饰this指针,所以... (11)如何修改常量? 有时候我们却不得不对类内的数据进行修改,但是我们的接口却被声明了const,那该怎么处理呢?我对这个问题的看法如下: 1)标准用法: mutable class A { public: A(int i=0):test(i) { } void SetValue(int i)const { test=i; } private: mutable int test;//这里处理! }; 2)强制转换: const_cast class A { public: A(int i=0):test(i) { } void SetValue(int i)const { const_cast (test)=i; }//这里处理! private: int test; }; 3)灵活的指针: int* class A { public: A(int i=0):test(i) { } void SetValue(int i)const { *test=i; } private: int* test; //这里处理! }; 4)未定义的处理 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { int *p=(int*)&test; *p=i; }//这里处理! private: int test; }; 注意,这里虽然说可以这样修改,但结果是未定义的,避免使用! 5)内部处理:this指针 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { ((A*)this)->test=i; }//这里处理! private: int test; }; 6)最另类的处理:空间布局 class A { public: A(int i=0):test(i),c("a") { } private: char c; const int test; }; int main() { A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);//利用边缘调整 *pi=5;//此处改变了test的值! return 0; } 虽然我给出了6中方法,但是我只是想说明如何更改,但出了第一种用法之外,另外5种用法,我们并不提倡,不要因为我这么写了,你就这么用,否则,我真是要误人子弟了:) (12)最后我们来讨论一下常量对象的动态创建。 既然编译器可以动态初始化常量,就自然可以动态创建,例如: const int* pi=new const int(10); 这里要注意2点: 1)const对象必须被初始化!所以(10)是不能够少的。 2)new返回的指针必须是const类型的。 那么我们可不可以动态创建一个数组呢? 答案是否定的,因为new内置类型的数组,不能被初始化。 这里我们忽视了数组是类类型的,同样对于类内部数组初始化我们也做出了这样的忽视,因为这涉及到数组的问题,我们以后再讨论。 来源:http://zhidao.baidu.com/question/91670015.html?si=32023-07-21 22:46:564
有谁可以详细的讲讲 const 作用和用法
从别的地方找来的,解释的很全面,你看看吧,看完应该就很明白了! 1、什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 2、为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 3、cons有什么主要的作用? (1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4、如何使用const? (1)修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; (2)修饰常数组 定义或说明一个常数组可采用如下格式: int const a[5]={1, 2, 3, 4, 5}; const int a[5]={1, 2, 3, 4, 5}; (3)修饰常对象 常对象是指对象常量,定义格式如下: class A; const A a; A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 (4)修饰常指针 const int *A; //const修饰指向的对象,A可变,A指向的对象不可变 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A;//指针A和A指向的对象都不可变 (5)修饰常引用 使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下: const double & v; (6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下: void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。 (7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; ..... }; 这样,在调用函数Fun时就不能修改类里面的数据 (9)在另一连接文件中引用const常量 extern const int i;//正确的引用 extern const int j=10;//错误!常量不可以被再次赋值 另外,还要注意,常量必须初始化! 例如: const int i=5; 5、几点值得讨论的地方: (1)const究竟意味着什么? 说了这么多,你认为const意味着什么?一种修饰符?接口抽象?一种新类型? 也许都是,在Stroustup最初引入这个关键字时,只是为对象放入ROM做出了一种可能,对于const对象,C++既允许对其进行静态初始化,也允许对他进行动态初始化。理想的const对象应该在其构造函数完成之前都是可写的,在析够函数执行开始后也都是可写的,换句话说,const对象具有从构造函数完成到析够函数执行之前的不变性,如果违反了这条规则,结果都是未定义的!虽然我们把const放入ROM中,但这并不能够保证const的任何形式的堕落,我们后面会给出具体的办法。无论const对象被放入ROM中,还是通过存储保护机制加以保护,都只能保证,对于用户而言这个对象没有改变。换句话说,废料收集器(我们以后会详细讨论,这就一笔带过)或数据库系统对一个const的修改怎没有任何问题。 (2)位元const V.S. 抽象const? 对于关键字const的解释有好几种方式,最常见的就是位元const 和 抽象const。下面我们看一个例子: class A { public: ...... A f(const A& a); ...... }; 如果采用抽象const进行解释,那就是f函数不会去改变所引用对象的抽象值,如果采用位元const进行解释,那就成了f函数不会去改变所引用对象的任何位元。 我们可以看到位元解释正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。 为什么这样呢?因为使用位元const有2个好处: 最大的好处是可以很容易地检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就可以了。另外,如果我们采用了位元const,那么,对于一些比较简单的const对象,我们就可以把它安全的放入ROM中,对于一些程序而言,这无疑是一个很重要的优化方式。(关于优化处理,我们到时候专门进行讨论) 当然,位元const也有缺点,要不然,抽象const也就没有产生的必要了。 首先,位元const的抽象性比抽象const的级别更低!实际上,大家都知道,一个库接口的抽象性级别越低,使用这个库就越困难。 其次,使用位元const的库接口会暴露库的一些实现细节,而这往往会带来一些负面效应。所以,在库接口和程序实现细节上,我们都应该采用抽象const。 有时,我们可能希望对const做出一些其它的解释,那么,就要注意了,目前,大多数对const的解释都是类型不安全的,这里我们就不举例子了,你可以自己考虑一下,总之,我们尽量避免对const的重新解释。 (3)放在类内部的常量有什么限制? 看看下面这个例子: class A { private: const int c3 = 7; // ??? static int c4 = 7; // ??? static const float c5 = 7; // ??? ...... }; 你认为上面的3句对吗?呵呵,都不对!使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式初始化的整型或枚举类型,而且必须是static和const形式。这显然是一个很严重的限制! 那么,我们的标准委员会为什么做这样的规定呢?一般来说,类在一个头文件中被声明,而头文件被包含到许多互相调用的单元去。但是,为了避免复杂的编译器规则,C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话,这种规则就被破坏了。 (4)如何初始化类内部的常量? 一种方法就是static 和 const 并用,在内部初始化,如上面的例子; 另一个很常见的方法就是初始化列表: class A { public: A(int i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,例如: class A { public: A() {} private: static const int i;//注意必须是静态的! }; const int A::i=3; (5)常量与数组的组合有什么特殊吗? 我们给出下面的代码: const int size[3]={10,20,50}; int array[size[2]]; 有什么问题吗?对了,编译通不过!为什么呢? Const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了:) 你再看看下面的例子: class A { public: A(int i=0):test[2]({1,2}) {}//你认为行吗? private: const int test[2]; }; vc6下编译通不过,为什么呢? 关于这个问题,前些时间,njboy问我是怎么回事?我反问他:“你认为呢?”他想了想,给出了一下解释,大家可以看看:我们知道编译器堆初始化列表的操作是在构造函数之内,显式调用可用代码之前,初始化的次序依据数据声明的次序。初始化时机应该没有什么问题,那么就只有是编译器对数组做了什么手脚!其实做什么手脚,我也不知道,我只好对他进行猜测:编译器搜索到test发现是一个非静态的数组,于是,为他分配内存空间,这里需要注意了,它应该是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],这就导致数组的初始化实际上是赋值!然而,常量不允许赋值,所以无法通过。 呵呵,看了这一段冠冕堂皇的话,真让我笑死了!njboy别怪我揭你短呀:)我对此的解释是这样的:C++标准有一个规定,不允许无序对象在类内部初始化,数组显然是一个无序的,所以这样的初始化是错误的!对于他,只能在类的外部进行初始化,如果想让它通过,只需要声明为静态的,然后初始化。 这里我们看到,常量与数组的组合没有什么特殊!一切都是数组惹的祸! (6)this指针是不是const类型的? this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。 (7)const到底是不是一个重载的参考对象? 先看一下下面的例子: class A { ...... void f(int i) {......}//一个函数 void f(int i) const {......}//上一个函数的重载 ...... }; 上面是重载是没有问题的了,那么下面的呢? class A { ...... void f(int i) {......}//一个函数 void f(const int i) {......}//????? ...... }; 这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子: class A { ...... void f(int& ) {......}//一个函数 void f(const int& ) {......}//????? ...... }; 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 (8)什么情况下为const分配内存? 以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。 A、作为非静态的类成员时; B、用于集合时; C、被取地址时; D、在main函数体内部通过函数来获得值时; E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。 F、当const的长度比计算机字长还长时; G、参数中的const; H、使用了extern时。 不知道还有没有其他情况,欢迎高手指点:) (9)临时变量到底是不是常量? 很多情况下,编译器必须建立临时对象。像其他任何对象一样,它们需要存储空间而且必须被构造和删除。区别是我们从来看不到编译器负责决定它们的去留以及它们存在的细节。对于C++标准草案而言:临时对象自动地成为常量。因为我们通常接触不到临时对象,不能使用与之相关的信息,所以告诉临时对象做一些改变有可能会出错。当然,这与编译器有关,例如:vc6、vc7都对此作了扩展,所以,用临时对象做左值,编译器并没有报错。 (10)与static搭配会不会有问题? 假设有一个类: class A { public: ...... static void f() const { ......} ...... }; 我们发现编译器会报错,因为在这种情况下static不能够与const共存! 为什么呢?因为static没有this指针,但是const修饰this指针,所以... (11)如何修改常量? 有时候我们却不得不对类内的数据进行修改,但是我们的接口却被声明了const,那该怎么处理呢?我对这个问题的看法如下: 1)标准用法: mutable class A { public: A(int i=0):test(i) { } void SetValue(int i)const { test=i; } private: mutable int test;//这里处理! }; 2)强制转换: const_cast class A { public: A(int i=0):test(i) { } void SetValue(int i)const { const_cast (test)=i; }//这里处理! private: int test; }; 3)灵活的指针: int* class A { public: A(int i=0):test(i) { } void SetValue(int i)const { *test=i; } private: int* test; //这里处理! }; 4)未定义的处理 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { int *p=(int*)&test; *p=i; }//这里处理! private: int test; }; 注意,这里虽然说可以这样修改,但结果是未定义的,避免使用! 5)内部处理:this指针 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { ((A*)this)->test=i; }//这里处理! private: int test; }; 6)最另类的处理:空间布局 class A { public: A(int i=0):test(i),c("a") { } private: char c; const int test; }; int main() { A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);//利用边缘调整 *pi=5;//此处改变了test的值! return 0; } 虽然我给出了6中方法,但是我只是想说明如何更改,但出了第一种用法之外,另外5种用法,我们并不提倡,不要因为我这么写了,你就这么用,否则,我真是要误人子弟了:) (12)最后我们来讨论一下常量对象的动态创建。 既然编译器可以动态初始化常量,就自然可以动态创建,例如: const int* pi=new const int(10); 这里要注意2点: 1)const对象必须被初始化!所以(10)是不能够少的。 2)new返回的指针必须是const类型的。 那么我们可不可以动态创建一个数组呢? 答案是否定的,因为new内置类型的数组,不能被初始化。 这里我们忽视了数组是类类型的,同样对于类内部数组初始化我们也做出了这样的忽视,因为这涉及到数组的问题,我们以后再讨论。2023-07-21 22:47:291
放在函数后面的const是什么意思
(1)可以定义 const 常量 (2)const 可以修饰函数的参数、返回值.详细内容: 1、什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 2、为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 3、cons有什么主要的作用? (1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4、如何使用const? (1)修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; (2)修饰常数组 定义或说明一个常数组可采用如下格式: int const a[5]={1, 2, 3, 4, 5}; const int a[5]={1, 2, 3, 4, 5}; (3)修饰常对象 常对象是指对象常量,定义格式如下: class A; const A a; A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 (4)修饰常指针 const int *A; //const修饰指向的对象,A可变,A指向的对象不可变 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A;//指针A和A指向的对象都不可变 (5)修饰常引用 使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下: const double & v; (6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下: void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。 (7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; ..... }; 这样,在调用函数Fun时就不能修改类里面的数据 (9)在另一连接文件中引用const常量 extern const int i;//正确的引用 extern const int j=10;//错误!常量不可以被再次赋值 另外,还要注意,常量必须初始化! 例如: const int i=5; 5、几点值得讨论的地方: (1)const究竟意味着什么? 说了这么多,你认为const意味着什么?一种修饰符?接口抽象?一种新类型? 也许都是,在Stroustup最初引入这个关键字时,只是为对象放入ROM做出了一种可能,对于const对象,C++既允许对其进行静态初始化,也允许对他进行动态初始化。理想的const对象应该在其构造函数完成之前都是可写的,在析够函数执行开始后也都是可写的,换句话说,const对象具有从构造函数完成到析够函数执行之前的不变性,如果违反了这条规则,结果都是未定义的!虽然我们把const放入ROM中,但这并不能够保证const的任何形式的堕落,我们后面会给出具体的办法。无论const对象被放入ROM中,还是通过存储保护机制加以保护,都只能保证,对于用户而言这个对象没有改变。换句话说,废料收集器(我们以后会详细讨论,这就一笔带过)或数据库系统对一个const的修改怎没有任何问题。 (2)位元const V.S. 抽象const? 对于关键字const的解释有好几种方式,最常见的就是位元const 和 抽象const。下面我们看一个例子: class A { public: ...... A f(const A& a); ...... }; 如果采用抽象const进行解释,那就是f函数不会去改变所引用对象的抽象值,如果采用位元const进行解释,那就成了f函数不会去改变所引用对象的任何位元。 我们可以看到位元解释正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。 为什么这样呢?因为使用位元const有2个好处: 最大的好处是可以很容易地检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就可以了。另外,如果我们采用了位元const,那么,对于一些比较简单的const对象,我们就可以把它安全的放入ROM中,对于一些程序而言,这无疑是一个很重要的优化方式。(关于优化处理,我们到时候专门进行讨论) 当然,位元const也有缺点,要不然,抽象const也就没有产生的必要了。 首先,位元const的抽象性比抽象const的级别更低!实际上,大家都知道,一个库接口的抽象性级别越低,使用这个库就越困难。 其次,使用位元const的库接口会暴露库的一些实现细节,而这往往会带来一些负面效应。所以,在库接口和程序实现细节上,我们都应该采用抽象const。 有时,我们可能希望对const做出一些其它的解释,那么,就要注意了,目前,大多数对const的解释都是类型不安全的,这里我们就不举例子了,你可以自己考虑一下,总之,我们尽量避免对const的重新解释。 (3)放在类内部的常量有什么限制? 看看下面这个例子: class A { private: const int c3 = 7; // ??? static int c4 = 7; // ??? static const float c5 = 7; // ??? ...... }; 你认为上面的3句对吗?呵呵,都不对!使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式初始化的整型或枚举类型,而且必须是static和const形式。这显然是一个很严重的限制! 那么,我们的标准委员会为什么做这样的规定呢?一般来说,类在一个头文件中被声明,而头文件被包含到许多互相调用的单元去。但是,为了避免复杂的编译器规则,C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话,这种规则就被破坏了。 (4)如何初始化类内部的常量? 一种方法就是static 和 const 并用,在内部初始化,如上面的例子; 另一个很常见的方法就是初始化列表: class A { public: A(int i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,例如: class A { public: A() {} private: static const int i;//注意必须是静态的! }; const int A::i=3; (5)常量与数组的组合有什么特殊吗? 我们给出下面的代码: const int size[3]={10,20,50}; int array[size[2]]; 有什么问题吗?对了,编译通不过!为什么呢? Const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了:) 你再看看下面的例子: class A { public: A(int i=0):test[2]({1,2}) {}//你认为行吗? private: const int test[2]; }; vc6下编译通不过,为什么呢? 关于这个问题,前些时间,njboy问我是怎么回事?我反问他:“你认为呢?”他想了想,给出了一下解释,大家可以看看:我们知道编译器堆初始化列表的操作是在构造函数之内,显式调用可用代码之前,初始化的次序依据数据声明的次序。初始化时机应该没有什么问题,那么就只有是编译器对数组做了什么手脚!其实做什么手脚,我也不知道,我只好对他进行猜测:编译器搜索到test发现是一个非静态的数组,于是,为他分配内存空间,这里需要注意了,它应该是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],这就导致数组的初始化实际上是赋值!然而,常量不允许赋值,所以无法通过。 呵呵,看了这一段冠冕堂皇的话,真让我笑死了!njboy别怪我揭你短呀:)我对此的解释是这样的:C++标准有一个规定,不允许无序对象在类内部初始化,数组显然是一个无序的,所以这样的初始化是错误的!对于他,只能在类的外部进行初始化,如果想让它通过,只需要声明为静态的,然后初始化。 这里我们看到,常量与数组的组合没有什么特殊!一切都是数组惹的祸! (6)this指针是不是const类型的? this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。 (7)const到底是不是一个重载的参考对象? 先看一下下面的例子: class A { ...... void f(int i) {......}//一个函数 void f(int i) const {......}//上一个函数的重载 ...... }; 上面是重载是没有问题的了,那么下面的呢? class A { ...... void f(int i) {......}//一个函数 void f(const int i) {......}//????? ...... }; 这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子: class A { ...... void f(int& ) {......}//一个函数 void f(const int& ) {......}//????? ...... }; 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 (8)什么情况下为const分配内存? 以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。 A、作为非静态的类成员时; B、用于集合时; C、被取地址时; D、在main函数体内部通过函数来获得值时; E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。 F、当const的长度比计算机字长还长时; G、参数中的const; H、使用了extern时。 不知道还有没有其他情况,欢迎高手指点:) (9)临时变量到底是不是常量? 很多情况下,编译器必须建立临时对象。像其他任何对象一样,它们需要存储空间而且必须被构造和删除。区别是我们从来看不到编译器负责决定它们的去留以及它们存在的细节。对于C++标准草案而言:临时对象自动地成为常量。因为我们通常接触不到临时对象,不能使用与之相关的信息,所以告诉临时对象做一些改变有可能会出错。当然,这与编译器有关,例如:vc6、vc7都对此作了扩展,所以,用临时对象做左值,编译器并没有报错。 (10)与static搭配会不会有问题? 假设有一个类: class A { public: ...... static void f() const { ......} ...... }; 我们发现编译器会报错,因为在这种情况下static不能够与const共存! 为什么呢?因为static没有this指针,但是const修饰this指针,所以... (11)如何修改常量? 有时候我们却不得不对类内的数据进行修改,但是我们的接口却被声明了const,那该怎么处理呢?我对这个问题的看法如下: 1)标准用法: mutable class A { public: A(int i=0):test(i) { } void SetValue(int i)const { test=i; } private: mutable int test;//这里处理! }; 2)强制转换: const_cast class A { public: A(int i=0):test(i) { } void SetValue(int i)const { const_cast (test)=i; }//这里处理! private: int test; }; 3)灵活的指针: int* class A { public: A(int i=0):test(i) { } void SetValue(int i)const { *test=i; } private: int* test; //这里处理! }; 4)未定义的处理 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { int *p=(int*)&test; *p=i; }//这里处理! private: int test; }; 注意,这里虽然说可以这样修改,但结果是未定义的,避免使用! 5)内部处理:this指针 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { ((A*)this)->test=i; }//这里处理! private: int test; }; 6)最另类的处理:空间布局 class A { public: A(int i=0):test(i),c("a") { } private: char c; const int test; }; int main() { A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);//利用边缘调整 *pi=5;//此处改变了test的值! return 0; } 虽然我给出了6中方法,但是我只是想说明如何更改,但出了第一种用法之外,另外5种用法,我们并不提倡,不要因为我这么写了,你就这么用,否则,我真是要误人子弟了:) (12)最后我们来讨论一下常量对象的动态创建。 既然编译器可以动态初始化常量,就自然可以动态创建,例如: const int* pi=new const int(10); 这里要注意2点: 1)const对象必须被初始化!所以(10)是不能够少的。 2)new返回的指针必须是const类型的。 那么我们可不可以动态创建一个数组呢? 答案是否定的,因为new内置类型的数组,不能被初始化。 这里我们忽视了数组是类类型的,同样对于类内部数组初始化我们也做出了这样的忽视,因为这涉及到数组的问题,我们以后再讨论。 来源:http://zhidao.baidu.com/question/91670015.html?si=32023-07-21 22:47:383
全局变量和const定义是什么?
全局变量的定义为本函数和其他函数所共用。const定义是指使用类型修饰符const说明的类型。一、全局变量全局变量是编程术语中的一种,源自于变量之分。变量分为局部与全局,局部变量又可称之为内部变量。变量由某对象或某个函数所创建的变量通常都是局部变量,只能被内部引用,而无法被其它对象或函数引用。全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用。二、CONST(C中的CONST)const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。const它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。清晰理解const所起的作用,对理解对方的程序也有一定帮助。CONST在其它编程语言中也有出现,例如Pascal、C++、PHP5、B#.net、HC08 C、C#等。2023-07-21 22:47:482
const和int的区别是什么?
一、区别如下:1、int定义的量是变量,它的值可以更改;而const int 定义的是一个常量,它的值不可以更改。2、int在定义的时候,不需要初始化,而const int 在定义的时候必须初始化;二、const的作用:把对象转换成一个常量拓展资料const与define。两者都可以用来定义常量,但是const定义时,定义了常量的类型,所以更精确一些。#define只是简单的文本替换,除了可以定义常量外,还可以用来定义一些简单的函数,有点类似内联函数(Inline)。const和define定义的常量可以放在头文件里面。参考资料:百度百科:CONST2023-07-21 22:48:031
c语言中const修饰的到底是常量还是变量?
C语言中const修饰的量是常变量,它与普通变量的编译方式一样,唯一的区别是常变量定义后不能做左值。C++中const修饰的才是常量。1、 const修饰的变量是常量还是变量对于这个问题,很多同学认为const修饰的变量是不能改变,结果就误认为该变量变成了常量。那么对于const修饰的变量该如何理解那?下面我们来看一个例子:int main{char buf[4];const int a = 0;a = 10;}这个比较容易理解,编译器直接报错,原因在于“a = 10;”这句话,对const修饰的变量,后面进行赋值操作。这好像说明了const修饰的变量是不能被修改的,那究竟是不是那,那么下面我们把这个例子修改下:int main{char buf[4];const int a = 0;buf[4] = 97;printf(“the a is %d ”,a);}其中最后一句printf的目的是看下变量a的值是否改变,根据const的理解,如果const修饰的是变量是不能被修改的话,那么a的值一定不会改变,肯定还是0。但是在实际运行的结果中,我们发现a的值已经变为97了。这说明const修饰的变量a,已经被我们程序修改了。那综合这两个例子,我们来分析下,对于第二例子,修改的原因是buf[4]的赋值操作,我们知道buf[4]这个变量已经造成了buf这个数组变量的越界访问。buf数组的成员本身只有0,1,2,3,那么buf[4]访问的是谁那,根据局部变量的地址分配,可以知道buf[4]的地址和int a的地址是一样,那么buf[4]实际上就是访问了const int a;那么对buf[4]的修改,自然也修改了const int a的空间,这也是为什么我们在最后打印a的值的时候看到了97这个结果。那么我们现在可以知道了,const修饰的变量是不具备不允许修改的特性的,那么对于第一个例子的现象我们又如何解释那。第一个例子,错误是在程序编译的时候给出的,注意这里,这个时候并没有生成可执行文件,说明const修饰的变量可否修改是由编译器来帮我们保护了。而第二个例子里,变量的修改是在可执行程序执行的时候修改的,说明a还是一个变量。综上所述,我们可以得出一个结论,那就是const修饰的变量,其实质是告诉程序员或编译器该变量为只读,如果程序员在程序中显示的修改一个只读变量,编译器会毫不留情的给出一个error。而对于由于像数组溢出,隐式修改等程序不规范书写造成的运行过程中的修改,编译器是无能为力的,也说明const修饰的变量仍然是具备变量属性的。2、 被const修饰的变量,会被操作系统保护,防止修改如果对于第一个问题,有了理解的话,那么这个问题,就非常容易知道答案了。Const修饰的变量是不会被操作系统保护的。其原因是操作系统只保护常量,而不会保护变量的读写。那么什么是常量?比如“hello world”这个字符串就是被称为字符串常量。对于这个问题的另一种证明方法,可以看下面这个程序:int main{const int a;char *buf = “hello world”;printf(“the &a is %p, the buf is %p ”,&a, buf);}可以发现buf保存的地址是在0x08048000这个地址附近的,而a的地址是在0xbf000000这个地址附近的,而0x08048000附近的地址在我们linux操作系统上是代码段。这也说明了常量和变量是存放在不同区域的,自然操作系统是会保护常量的。2023-07-21 22:48:511
C++语言中,const后面可以不用加类型名(int 之类的)吗?
const &a 等价于 const int &a这两个没有区别,在变量声明中const int 的int可以省略,默认为int类型。注:其它类型不可省略。2023-07-21 22:49:012
c语言中const、static关键字的用法?
const是指常数,这种数存放在rom中,也就是硬盘里,只有使用的时候才读取到内存。static类型的是局部静态数据,首先他肯定是局部变量,但是他的生存期是全局的。const数不能被修改,也不能是局部变量。static一般用于局部变量,但是他可以被修改,并且退出引用他的函数体后变量依旧存在,直到下一次引用时数值不变化。2023-07-21 22:49:221
c++中const是怎么使用的
你好,首先你应当明白引用时C++区别于C的一点。但是在Lippleman的中曾经指出,引用的实现说到底还是采用指针实现的,但是它比指针有自己的优势。然后再Lippleman的中他指出现代C++程序偏向于使用引用,而不是指针,但是并不是说指针不再使用。C++中的const关键字是指出对象时一个常量,是不允许变动它在内存当中的值的。但是还有很多点是需要注意的。1.指向const对象的指针 const double *ptr表明ptr指向一个double类型的对象,你可以赋值给ptr一个常量或者不是常量。比如:double temp = 3.0;const double *ptr = &temp; //此时你不能通过ptr来更改temp的值,也就是说下面的语句是错误的:*ptr = 4.0;但是temp本身并不是const变量,下面的语句就是对的:temp = 4.0; //注意const对象一定要在对象的初始化时赋值.就是说下面的语句是错误的:double temp = 3.0;const double* ptr; ptr = &temp; //error2.const指针 ,和一般的const对象一样,说明指针本身是const,是不允许指向其他的对象的;比如下面的语句就是错的:double temp = 3.0;double* const ptr = &temp; double err = 4.0;ptr = &err; //注意const对象的初始化时一定需要赋值.但是你可以使用ptr来更改temp的值,就是说下面的语句是对的:*ptr = 10.0;对于你上面的例子中,首先你应该知道C++的标识符的命名本身就应该包含足够的信息,而不是随便的a,b,等没有用的名字。函数print()就是说该函数是用来打印的,并不会更改对象的内容,所以你将函数的形参设为const,是为了当你在函数的实现中一不小心更改了对象的内容,编译器会及时的报错,从而能避免以后不需要的麻烦。在标准的C中,函数形参的const说明是会被编译器直接忽略的就是说你写成const,但是你还是可以在函数的实现中更改对象的内容,但是你的const说明符告诉函数的使用者该专递给函数一个const对象,但是编译器并不负责对你的更改操作给出error提示的.在C++中,确实会给出提示的。所以当你的函数并不会改变对象的内容时,将其定义为const对象回事很好的编程习惯的。2023-07-21 22:49:291
vb 中const用法
是常量的意思,而VB中的常量还有以下几种: 1)直接常量 指在程序中直接给出值的数据,如:123、123&、123.45、1.234E2 、123D3分别表示整型、长整型、单精度浮点型(小数形式)、单精度浮点型(指数形式)、双精度浮点型。 八进制常数: 在数值前加&O ,如 &O123 十六进制常数:在数值前加&H ,如&H123 2)用户声明的符号常量 用Const来声明: Const 符号常量名 [As 类型] = 表达式 如:Const PI=3.14159 "声明了常量PI,代表3.14159,单精度型 Const MAX As Integer=&O144 ""声明了常量MAX,代表八进制数144,整型 Const COUNT#=45.67 "声明了常量COUNT,代表45.67,双精度型 3)系统提供的常量 系统定义的常量位于对象库中,在对象浏览器中的Visual Basic(VB)和Visual Basic for Aplication(VBA)等对象库中列出了VB的常量。这些常量可以与应用程序的对象、方法、属性一起使用。 如:Form1.WindowsState=vbMaximized 表示将窗口极大化。2023-07-21 22:49:373
C++返回值为Const &的看法大虾给解释下
既然LZ分有多,同一问题提2遍,那我也回答两遍吧。分一旦用来悬赏,系统可是不退的哦~~首先&的引用作用是C++独有的特性。其作用相当于传入参数时不经过拷贝,而是实实在在的传入。就像LZ的例子中的fun(int &a)。如果在函数内部修改了a的值,那就确实修改了a的值。而一般的参数传入方式都是传入一个参数的副本。函数内部的操作都是作用于副本。我对LZ的某些话有点难以理解,比如“普通变量形参在传递的过程 需要重新申请一个”我猜测LZ的意思其实就是普通变量形参在传递的过程 传递的其实是参数的拷贝。不过如果LZ既然已经知道这层意思,那么后面的疑问又从何而来。这不是显而易见的吗?所以我感觉LZ压根没把引用的作用弄明白,所以才在上面说了一大堆。对于返回值,也类似。一般返回值也是返回的拷贝值。所以如果将函数内的局部变量以引用方式返回是没有意义的。因为退出函数后,函数内部的局部变量已经被系统回收,所以这样引用方式传出的变量也是无效的。但是一般方式返回的变量反而是有效的。因为一般方式返回的是拷贝值,即使原版已经被销毁也无所谓。但是,有种情况是个例外。那就是对于生命周期足够长的变量,引用返回就是有效的。比如LZ例子里的int& fun(int &a){return a;},这里的a因为是引用方式传入,所以他的生命周期是大于函数本身的。所以引用方式传出也没有问题。当然其实这个例子一般不常见。真正常见的是下面的例子:class A{public:A():m_data(0){}int m_data;int &get() {return m_data;}}这里的m_data的生命周期和类A实例化后的变量一样长,所以显然是长于函数get的。所以引用返回是有效的。而且类似引用传入,少了拷贝的步骤,效率更高。当然本例中int本身不复杂,效率没啥区别。但若是一个相当复杂的结构体,那效率差别就大了。当然引用返回最大的作用就在下面:A a;a.get(a) += 1; //这样是合法的。这就是引用返回的最大作用。可以对返回值直接做这样的操作。专业点的话就是,可以直接当作左值。这可是相当有用的。完全看不出傻在哪里~~~说这样傻正说明LZ的不成熟吧。下面可以来个更具体的例子:struct B{B();int m_data[10];int& operator [] (int i){return m_data[i];}}void main(){B b;b[0] = 1;b[1] = 2; //怎么样,爽吧。}当然 若返回类型变为const &,就失去了左值的作用。但是省去拷贝,增加效率的作用还是在的2023-07-21 22:49:442
通达信公式中“CONST”是什么含义
通达信公式中“CONST” 意义为取值设为常数。CONST(C); 收盘价的最后一日取值设为常数以上为例,只显示最后一个数为值。公式中用到这个函数的地方不多。2023-07-21 22:49:532
constexpr和const数组的区别?
const是表明这个值是constant的,但是不必在编译期确定,然而数组的大小是需要在编译期确定的,如:int i; // not constantconst int size = i; // fine!int arr[size]; // Error!然而对于constexpr,则表明这个值不仅是constant的,而且也是编译期确定的int i; // not constantconstexpr int size = i; // Error!于是,constexpr修饰的是可以用于数组大小的。而为什么在main的const是可以的呢?其实这跟const无关,而是使用了C99的一个特性,名叫variable length array(简称VLA),所以即使是这样:int main(){ int i; cin >> i; int arr[i];}你使用你现在的GCC编译,也是可以通过的那么,为什么VLA的数组不能在全局区呢?那么我想从两方面来解释:1. 标准文档在C11标准文档的 6.7.6.2 Array declarators2. If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.10. All declarations of variably modified (VM) types have to be at either block scope orfunction prototype scope. Array objects declared with the _Thread_local, static, or externstorage-class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage-class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.2. 原理解释GCC实现VLA的方式,是allocate memory在stack上,所以,隐藏在VLA下面的是也发生了Memory Allocation的动作,所以你怎么能在全局区去进行Memory Allocation呢?最后,再补充一些constexpr的东西。这是一个C++11引入的东西,C++14对constexpr的范围进行了更大程度的条件放松,而这里我就仅谈C++11的。刚才谈到了constexpr是限定了修饰的为编译期间可确定的常量,但是constexpr也是可以用于函数的,而这个时候就不一定可以保证最后的值是constexpr了,那么我那次开C++11讲座的时候,介绍的一个小技巧,就是用数组检测是不是编译期的常量,这也是利用了数组大小需要编译期间确定的特点:constexpr int sz() { return 47;};constexpr size_t scale(size_t cnt){ return sz() * cnt;}const int i = 3;int arr[scale(i)]; // OKint j = 3;int arr[scale(j)]; //Error!2023-07-21 22:50:001
const在C语言中有哪些用法?
1、定义常量用const可以定义各种类型的常量例如:const int MAX = 100;const float MIN = 0;并且编译时会进行类型检查,这是其和#define的最大不同,当然它也没有#define定义宏的功能。2、用于防止向函数传递的参数被意外修改例如:int fun(const int *p1,const int *p2);这样定义这个函数,可以防止传递进来的指针所指向的内容被意外修改因为如果你进行了修改,编译时会报错2023-07-21 22:50:115
如何定义const数据在 gconst段里
const 表示常量,相当于宏定义,只能读取,不能修改。常变量:const 数据类型 符号常变量 = 数值如:const float PI=3.14;指针常量:数据类型 *const 指针变量=变量名如:char *const p="abc";const修饰的是指针变量,而不是指针的值,所以指针指向的值是可以修改的。常指针:const 数据类型 *指针变量=变量名或者是数据类型 const *指针变量=变量名这是指针指向的值就是不可以改变的。还有一种情况就是指针变量本身不可以修改,指针指向的值也是不允许修改的,就是指针常量和常指针组合,这种称为常指针常量:const 数据类型 *const 指针变量=变量名或数据类型 const *const 指针变量=变量名2023-07-21 22:50:261
怎么用const
const 的使用const经常用来修饰一个值不能改变的量,安全,并且能消除存储操作const的几种用法:(1) 说明值常量(2) 说明指针(3) 说明函数参数及其返回值(4) 说明类的常量和成员函数(1)最简单const int x = 10;x在程序运行过程中,永远等于10.其他的你是看看我给的链接2023-07-21 22:50:342
const 有什么用途?
const int n;n的值不可改2023-07-21 22:50:425
“const”是什么意思?
名词,有以下几种含义:常数,常量,结构,构造,康铜,铜镍合金,建筑,建筑物 。c语言中const 的含义及用法:const 表示常量,相当于宏定义,只能读取,不能修改。常变量:const 数据类型 符号常变量 = 数值,如:const float PI=3.14;指针常量:数据类型 *const 指针变量=变量名,如:char *const p="abc";const修饰的是指针变量,而不是指针的值,所以指针指向的值是可以修改的。常指针:const 数据类型 *指针变量=变量名或者是数据类型 const *指针变量=变量名,这是指针指向的值就是不可以改变的。还有一种情况就是指针变量本身不可以修改,指针指向的值也是不允许修改的,就是指针常量和常指针组合,这种称为常指针常量:const 数据类型 *const 指针变量=变量名或数据类型 const *const 指针变量=变量名2023-07-21 22:51:081
VB中const的具体意思和功能!高手进!
Const是用来定义常量的相对于变量来说变量在程序的运行过程中是可以发生改变的而常量是不能发生改变的它是一个固定的值 不可以用来参加赋值上的计算 比如PI的值(即圆周率)2023-07-21 22:51:332
C语言函数返回值为 const 型 有什么意义
当为指针时,有意义,一般数值没有意义当返回为const指针时,表示对返回指针所指向的数据内容不要进行修改。有修改则程序会报错!2023-07-21 22:51:422
c语言中const 是什么意思,怎么用,什么时候用?
const在pascal 中是常量说明。2023-07-21 22:51:533
请问c 语言中的 const 是什么意思?
常量定义详细内容: 1、什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 2、为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 3、cons有什么主要的作用? (1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4、如何使用const? (1)修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; (2)修饰常数组 定义或说明一个常数组可采用如下格式: int const a[5]={1, 2, 3, 4, 5}; const int a[5]={1, 2, 3, 4, 5}; (3)修饰常对象 常对象是指对象常量,定义格式如下: class A; const A a; A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 (4)修饰常指针 const int *A; //const修饰指向的对象,A可变,A指向的对象不可变 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A;//指针A和A指向的对象都不可变 (5)修饰常引用 使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下: const double & v; (6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下: void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。 (7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; ..... }; 这样,在调用函数Fun时就不能修改类里面的数据 (9)在另一连接文件中引用const常量 extern const int i;//正确的引用 extern const int j=10;//错误!常量不可以被再次赋值 另外,还要注意,常量必须初始化! 例如: const int i=5; 5、几点值得讨论的地方: (1)const究竟意味着什么? 说了这么多,你认为const意味着什么?一种修饰符?接口抽象?一种新类型? 也许都是,在Stroustup最初引入这个关键字时,只是为对象放入ROM做出了一种可能,对于const对象,C++既允许对其进行静态初始化,也允许对他进行动态初始化。理想的const对象应该在其构造函数完成之前都是可写的,在析够函数执行开始后也都是可写的,换句话说,const对象具有从构造函数完成到析够函数执行之前的不变性,如果违反了这条规则,结果都是未定义的!虽然我们把const放入ROM中,但这并不能够保证const的任何形式的堕落,我们后面会给出具体的办法。无论const对象被放入ROM中,还是通过存储保护机制加以保护,都只能保证,对于用户而言这个对象没有改变。换句话说,废料收集器(我们以后会详细讨论,这就一笔带过)或数据库系统对一个const的修改怎没有任何问题。 (2)位元const V.S. 抽象const? 对于关键字const的解释有好几种方式,最常见的就是位元const 和 抽象const。下面我们看一个例子: class A { public: ...... A f(const A& a); ...... }; 如果采用抽象const进行解释,那就是f函数不会去改变所引用对象的抽象值,如果采用位元const进行解释,那就成了f函数不会去改变所引用对象的任何位元。 我们可以看到位元解释正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。 为什么这样呢?因为使用位元const有2个好处: 最大的好处是可以很容易地检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就可以了。另外,如果我们采用了位元const,那么,对于一些比较简单的const对象,我们就可以把它安全的放入ROM中,对于一些程序而言,这无疑是一个很重要的优化方式。(关于优化处理,我们到时候专门进行讨论) 当然,位元const也有缺点,要不然,抽象const也就没有产生的必要了。 首先,位元const的抽象性比抽象const的级别更低!实际上,大家都知道,一个库接口的抽象性级别越低,使用这个库就越困难。 其次,使用位元const的库接口会暴露库的一些实现细节,而这往往会带来一些负面效应。所以,在库接口和程序实现细节上,我们都应该采用抽象const。 有时,我们可能希望对const做出一些其它的解释,那么,就要注意了,目前,大多数对const的解释都是类型不安全的,这里我们就不举例子了,你可以自己考虑一下,总之,我们尽量避免对const的重新解释。 (3)放在类内部的常量有什么限制? 看看下面这个例子: class A { private: const int c3 = 7; // ??? static int c4 = 7; // ??? static const float c5 = 7; // ??? ...... }; 你认为上面的3句对吗?呵呵,都不对!使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式初始化的整型或枚举类型,而且必须是static和const形式。这显然是一个很严重的限制! 那么,我们的标准委员会为什么做这样的规定呢?一般来说,类在一个头文件中被声明,而头文件被包含到许多互相调用的单元去。但是,为了避免复杂的编译器规则,C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话,这种规则就被破坏了。 (4)如何初始化类内部的常量? 一种方法就是static 和 const 并用,在内部初始化,如上面的例子; 另一个很常见的方法就是初始化列表: class A { public: A(int i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,例如: class A { public: A() {} private: static const int i;//注意必须是静态的! }; const int A::i=3; (5)常量与数组的组合有什么特殊吗? 我们给出下面的代码: const int size[3]={10,20,50}; int array[size[2]]; 有什么问题吗?对了,编译通不过!为什么呢? Const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了:) 你再看看下面的例子: class A { public: A(int i=0):test[2]({1,2}) {}//你认为行吗? private: const int test[2]; }; vc6下编译通不过,为什么呢? 关于这个问题,前些时间,njboy问我是怎么回事?我反问他:“你认为呢?”他想了想,给出了一下解释,大家可以看看:我们知道编译器堆初始化列表的操作是在构造函数之内,显式调用可用代码之前,初始化的次序依据数据声明的次序。初始化时机应该没有什么问题,那么就只有是编译器对数组做了什么手脚!其实做什么手脚,我也不知道,我只好对他进行猜测:编译器搜索到test发现是一个非静态的数组,于是,为他分配内存空间,这里需要注意了,它应该是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],这就导致数组的初始化实际上是赋值!然而,常量不允许赋值,所以无法通过。 呵呵,看了这一段冠冕堂皇的话,真让我笑死了!njboy别怪我揭你短呀:)我对此的解释是这样的:C++标准有一个规定,不允许无序对象在类内部初始化,数组显然是一个无序的,所以这样的初始化是错误的!对于他,只能在类的外部进行初始化,如果想让它通过,只需要声明为静态的,然后初始化。 这里我们看到,常量与数组的组合没有什么特殊!一切都是数组惹的祸! (6)this指针是不是const类型的? this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。 (7)const到底是不是一个重载的参考对象? 先看一下下面的例子: class A { ...... void f(int i) {......}//一个函数 void f(int i) const {......}//上一个函数的重载 ...... }; 上面是重载是没有问题的了,那么下面的呢? class A { ...... void f(int i) {......}//一个函数 void f(const int i) {......}//????? ...... }; 这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子: class A { ...... void f(int& ) {......}//一个函数 void f(const int& ) {......}//????? ...... }; 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 (8)什么情况下为const分配内存? 以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。 A、作为非静态的类成员时; B、用于集合时; C、被取地址时; D、在main函数体内部通过函数来获得值时; E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。 F、当const的长度比计算机字长还长时; G、参数中的const; H、使用了extern时。 不知道还有没有其他情况,欢迎高手指点:) (9)临时变量到底是不是常量? 很多情况下,编译器必须建立临时对象。像其他任何对象一样,它们需要存储空间而且必须被构造和删除。区别是我们从来看不到编译器负责决定它们的去留以及它们存在的细节。对于C++标准草案而言:临时对象自动地成为常量。因为我们通常接触不到临时对象,不能使用与之相关的信息,所以告诉临时对象做一些改变有可能会出错。当然,这与编译器有关,例如:vc6、vc7都对此作了扩展,所以,用临时对象做左值,编译器并没有报错。 (10)与static搭配会不会有问题? 假设有一个类: class A { public: ...... static void f() const { ......} ...... }; 我们发现编译器会报错,因为在这种情况下static不能够与const共存! 为什么呢?因为static没有this指针,但是const修饰this指针,所以... (11)如何修改常量? 有时候我们却不得不对类内的数据进行修改,但是我们的接口却被声明了const,那该怎么处理呢?我对这个问题的看法如下: 1)标准用法: mutable class A { public: A(int i=0):test(i) { } void SetValue(int i)const { test=i; } private: mutable int test;//这里处理! }; 2)强制转换: const_cast class A { public: A(int i=0):test(i) { } void SetValue(int i)const { const_cast (test)=i; }//这里处理! private: int test; }; 3)灵活的指针: int* class A { public: A(int i=0):test(i) { } void SetValue(int i)const { *test=i; } private: int* test; //这里处理! }; 4)未定义的处理 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { int *p=(int*)&test; *p=i; }//这里处理! private: int test; }; 注意,这里虽然说可以这样修改,但结果是未定义的,避免使用! 5)内部处理:this指针 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { ((A*)this)->test=i; }//这里处理! private: int test; }; 6)最另类的处理:空间布局 class A { public: A(int i=0):test(i),c("a") { } private: char c; const int test; }; int main() { A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);//利用边缘调整 *pi=5;//此处改变了test的值! return 0; } 虽然我给出了6中方法,但是我只是想说明如何更改,但出了第一种用法之外,另外5种用法,我们并不提倡,不要因为我这么写了,你就这么用,否则,我真是要误人子弟了:) (12)最后我们来讨论一下常量对象的动态创建。 既然编译器可以动态初始化常量,就自然可以动态创建,例如: const int* pi=new const int(10); 这里要注意2点: 1)const对象必须被初始化!所以(10)是不能够少的。 2)new返回的指针必须是const类型的。 那么我们可不可以动态创建一个数组呢? 答案是否定的,因为new内置类型的数组,不能被初始化。 这里我们忽视了数组是类类型的,同样对于类内部数组初始化我们也做出了这样的忽视,因为这涉及到数组的问题,我们以后再讨论。 来源:http://zhidao.baidu.com/question/91670015.html?si=32023-07-21 22:52:104
const和int有什么不同啊?
一、const int 和int 的区别具体的是 int定义的是一个变量,不需要初始化const int定义的是常量,需要初始化1、返回值const int & 是返回这个数值的一个常量的引用。而int 是返回这个数值的一个拷贝。int 是进行拷贝构造,而const int & 是返回的引用。拷贝构造更消耗时间,与此同时还用析构函数。因为产生了一个拷贝,你就可以轻易地修改拷贝的内容。2、取指针const int类型一旦定义以后就不能修改,int类型是随时可以修改的。在取指针方面,const有略复杂的东西,但是常规的、合理的操作不应该涉及到,因为const int是用来保存一些全局常量的,这些常量在编译期可以改,在运行期不能改。听起来这像宏,其实这确实就是用来取代宏的: #define PI 3.14 const float Pi = 3.14; 如果你的代码里用到了100次PI(宏),你的代码中会保存100个3.14这个常数。鉴于使用常数进行运算的机器代码很多时候会比使用变量来的长,如果你换用100次Pi(const float),程序编译后的机器码里就不需要出现100次常量3.14,只要在需要的时候引用存有3.14的常量就行了。特别在复杂的运算里,3.14这个常量(其实是无法修改的变量)会被一直装载在寄存器里带来一些性能提升。3、内容constint* p; //p可变,p指向的内容不可变,int const* p; //p可变,p指向的内容不可变。 int* const p; //p不可变,p指向的内容可变 const int* const p; //p和p指向的内容都不可变。二、const的作用:1、可以定义const常量,具有不可变性。例如:const int Max=100; Max++会产生错误;2、便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改;3、可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如1中,如果想修改Max的内容,只需要它修改成:const int Max=you want;即可!4、可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错;例如: void f(const int i) { i=10;//error! }2023-07-21 22:52:181
全局变量和const定义是什么
全局变量的定义为本函数和其他函数所共用。const定义是指使用类型修饰符const说明的类型。一、全局变量全局变量是编程术语中的一种,源自于变量之分。变量分为局部与全局,局部变量又可称之为内部变量。变量由某对象或某个函数所创建的变量通常都是局部变量,只能被内部引用,而无法被其它对象或函数引用。全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用。二、CONST(C中的CONST)const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。const它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。清晰理解const所起的作用,对理解对方的程序也有一定帮助。CONST在其它编程语言中也有出现,例如Pascal、C++、PHP5、B#.net、HC08 C、C#等。2023-07-21 22:52:301
CONST的主要作用
(1)可以定义const常量,具有不可变性。 例如:const int Max=100; Max++会产生错误; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。 例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变! 如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const double Pi=3.14159; //此时并未将Pi放入RAM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。 (6) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。2023-07-21 22:52:561
C语言函数返回值为 const 型 有什么意义
(1)可以定义const常量(2)const可以修饰函数的参数、返回值.详细内容:1、什么是const?常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:)2、为什么引入const?const推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。3、cons有什么主要的作用?(1)可以定义const常量,具有不可变性。例如:constintMax=100;intArray[Max];2023-07-21 22:53:121
const和int有什么区别?
一、区别如下:1、int定义的量是变量,它的值可以更改;而const int 定义的是一个常量,它的值不可以更改。2、int在定义的时候,不需要初始化,而const int 在定义的时候必须初始化;二、const的作用:把对象转换成一个常量拓展资料const与define。两者都可以用来定义常量,但是const定义时,定义了常量的类型,所以更精确一些。#define只是简单的文本替换,除了可以定义常量外,还可以用来定义一些简单的函数,有点类似内联函数(Inline)。const和define定义的常量可以放在头文件里面。参考资料:百度百科:CONST2023-07-21 22:53:191
c语言中const 是什么意思?
const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。另外CONST在其他编程语言中也有出现,如C++、PHP5、C#.net、HC08 C。 (1)可以定义const常量,具有不可变性。 例如:const int Max=100; Max++会产生错误; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。 例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变! 如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! }2023-07-21 22:53:352
C语言中 const可以直接修饰数据类型吗?
const不是C支持得,只能修饰变量,不能修饰类型2023-07-21 22:53:493
大学物理v=const指什么?
大学物理中v=const通常指的是物体的速度为常数,即匀速直线运动。在匀速直线运动中,物体的速度大小和方向都保持不变,因此速度为常数。这与加速度为零有关,即物体受到的合外力为零,使其速度不发生变化。2023-07-21 22:53:561
全局变量和const定义是什么?
全局变量的定义为本函数和其他函数所共用。const定义是指使用类型修饰符const说明的类型。一、全局变量全局变量是编程术语中的一种,源自于变量之分。变量分为局部与全局,局部变量又可称之为内部变量。变量由某对象或某个函数所创建的变量通常都是局部变量,只能被内部引用,而无法被其它对象或函数引用。全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用。二、CONST(C中的CONST)const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。const它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。清晰理解const所起的作用,对理解对方的程序也有一定帮助。CONST在其它编程语言中也有出现,例如Pascal、C++、PHP5、B#.net、HC08 C、C#等。2023-07-21 22:54:051
static const和const static的区别
对于C/C++语言来讲,const就是只读的意思,只在声明中使用;static一般有2个作用,规定作用域和存储方式.对于局部变量,static规定其为静态存储方式,每次调用的初始值为上一次调用的值,调用结束后存储空间不释放;对于全局变量,如果以文件划分作用域的话,此变量只在当前文件可见;对于static函数也是在当前模块内函数可见.static const 应该就是上面两者的合集.下面分别说明:全局:const,只读的全局变量,其值不可修改.static,规定此全局变量只在当前模块(文件)中可见.static const,既是只读的,又是只在当前模块中可见的.文件:文件指针可当作一个变量来看,与上面所说类似.函数:const,返回只读变量的函数.static,规定此函数只在当前模块可见.类:const,一般不修饰类,(在VC6.0中试了一下,修饰类没啥作用)static,C++中似乎没有静态类这个说法,一般还是拿类当特殊的变量来看.C#中有静态类的详细说明,且用法与普通类大不相同.2023-07-21 22:54:121
const和int的区别
const和int是C++中的两种变量类型。int是一种整型变量,可以存储整数值。而const则是一种常量,其值在程序执行过程中不能被改变。常量一般会在编译时进行初始化,不能被修改,而且常量一般会被存储在常量区。另外,const int a = 5; 与 int const a = 5; 意思是相同的。2023-07-21 22:54:191
const有什么用
(1)可以定义 const 常量 (2)const 可以修饰函数的参数、返回值.详细内容: 1、什么是const? 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 2、为什么引入const? const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 3、cons有什么主要的作用? (1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可! (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 4、如何使用const? (1)修饰一般常量 一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如: int const x=2; 或 const int x=2; (2)修饰常数组 定义或说明一个常数组可采用如下格式: int const a[5]={1, 2, 3, 4, 5}; const int a[5]={1, 2, 3, 4, 5}; (3)修饰常对象 常对象是指对象常量,定义格式如下: class A; const A a; A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。 (4)修饰常指针 const int *A; //const修饰指向的对象,A可变,A指向的对象不可变 int const *A; //const修饰指向的对象,A可变,A指向的对象不可变 int *const A; //const修饰指针A, A不可变,A指向的对象可变 const int *const A;//指针A和A指向的对象都不可变 (5)修饰常引用 使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下: const double & v; (6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下: void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。 (7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下: const int Fun1(); const MyClass Fun2(); (8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下: class ClassName { public: int Fun() const; ..... }; 这样,在调用函数Fun时就不能修改类里面的数据 (9)在另一连接文件中引用const常量 extern const int i;//正确的引用 extern const int j=10;//错误!常量不可以被再次赋值 另外,还要注意,常量必须初始化! 例如: const int i=5; 5、几点值得讨论的地方: (1)const究竟意味着什么? 说了这么多,你认为const意味着什么?一种修饰符?接口抽象?一种新类型? 也许都是,在Stroustup最初引入这个关键字时,只是为对象放入ROM做出了一种可能,对于const对象,C++既允许对其进行静态初始化,也允许对他进行动态初始化。理想的const对象应该在其构造函数完成之前都是可写的,在析够函数执行开始后也都是可写的,换句话说,const对象具有从构造函数完成到析够函数执行之前的不变性,如果违反了这条规则,结果都是未定义的!虽然我们把const放入ROM中,但这并不能够保证const的任何形式的堕落,我们后面会给出具体的办法。无论const对象被放入ROM中,还是通过存储保护机制加以保护,都只能保证,对于用户而言这个对象没有改变。换句话说,废料收集器(我们以后会详细讨论,这就一笔带过)或数据库系统对一个const的修改怎没有任何问题。 (2)位元const V.S. 抽象const? 对于关键字const的解释有好几种方式,最常见的就是位元const 和 抽象const。下面我们看一个例子: class A { public: ...... A f(const A& a); ...... }; 如果采用抽象const进行解释,那就是f函数不会去改变所引用对象的抽象值,如果采用位元const进行解释,那就成了f函数不会去改变所引用对象的任何位元。 我们可以看到位元解释正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。 为什么这样呢?因为使用位元const有2个好处: 最大的好处是可以很容易地检测到违反位元const规定的事件:编译器只用去寻找有没有对数据成员的赋值就可以了。另外,如果我们采用了位元const,那么,对于一些比较简单的const对象,我们就可以把它安全的放入ROM中,对于一些程序而言,这无疑是一个很重要的优化方式。(关于优化处理,我们到时候专门进行讨论) 当然,位元const也有缺点,要不然,抽象const也就没有产生的必要了。 首先,位元const的抽象性比抽象const的级别更低!实际上,大家都知道,一个库接口的抽象性级别越低,使用这个库就越困难。 其次,使用位元const的库接口会暴露库的一些实现细节,而这往往会带来一些负面效应。所以,在库接口和程序实现细节上,我们都应该采用抽象const。 有时,我们可能希望对const做出一些其它的解释,那么,就要注意了,目前,大多数对const的解释都是类型不安全的,这里我们就不举例子了,你可以自己考虑一下,总之,我们尽量避免对const的重新解释。 (3)放在类内部的常量有什么限制? 看看下面这个例子: class A { private: const int c3 = 7; // ??? static int c4 = 7; // ??? static const float c5 = 7; // ??? ...... }; 你认为上面的3句对吗?呵呵,都不对!使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式初始化的整型或枚举类型,而且必须是static和const形式。这显然是一个很严重的限制! 那么,我们的标准委员会为什么做这样的规定呢?一般来说,类在一个头文件中被声明,而头文件被包含到许多互相调用的单元去。但是,为了避免复杂的编译器规则,C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话,这种规则就被破坏了。 (4)如何初始化类内部的常量? 一种方法就是static 和 const 并用,在内部初始化,如上面的例子; 另一个很常见的方法就是初始化列表: class A { public: A(int i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,例如: class A { public: A() {} private: static const int i;//注意必须是静态的! }; const int A::i=3; (5)常量与数组的组合有什么特殊吗? 我们给出下面的代码: const int size[3]={10,20,50}; int array[size[2]]; 有什么问题吗?对了,编译通不过!为什么呢? Const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了:) 你再看看下面的例子: class A { public: A(int i=0):test[2]({1,2}) {}//你认为行吗? private: const int test[2]; }; vc6下编译通不过,为什么呢? 关于这个问题,前些时间,njboy问我是怎么回事?我反问他:“你认为呢?”他想了想,给出了一下解释,大家可以看看:我们知道编译器堆初始化列表的操作是在构造函数之内,显式调用可用代码之前,初始化的次序依据数据声明的次序。初始化时机应该没有什么问题,那么就只有是编译器对数组做了什么手脚!其实做什么手脚,我也不知道,我只好对他进行猜测:编译器搜索到test发现是一个非静态的数组,于是,为他分配内存空间,这里需要注意了,它应该是一下分配完,并非先分配test[0],然后利用初始化列表初始化,再分配test[1],这就导致数组的初始化实际上是赋值!然而,常量不允许赋值,所以无法通过。 呵呵,看了这一段冠冕堂皇的话,真让我笑死了!njboy别怪我揭你短呀:)我对此的解释是这样的:C++标准有一个规定,不允许无序对象在类内部初始化,数组显然是一个无序的,所以这样的初始化是错误的!对于他,只能在类的外部进行初始化,如果想让它通过,只需要声明为静态的,然后初始化。 这里我们看到,常量与数组的组合没有什么特殊!一切都是数组惹的祸! (6)this指针是不是const类型的? this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。 (7)const到底是不是一个重载的参考对象? 先看一下下面的例子: class A { ...... void f(int i) {......}//一个函数 void f(int i) const {......}//上一个函数的重载 ...... }; 上面是重载是没有问题的了,那么下面的呢? class A { ...... void f(int i) {......}//一个函数 void f(const int i) {......}//????? ...... }; 这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子: class A { ...... void f(int& ) {......}//一个函数 void f(const int& ) {......}//????? ...... }; 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 (8)什么情况下为const分配内存? 以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。 A、作为非静态的类成员时; B、用于集合时; C、被取地址时; D、在main函数体内部通过函数来获得值时; E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。 F、当const的长度比计算机字长还长时; G、参数中的const; H、使用了extern时。 不知道还有没有其他情况,欢迎高手指点:) (9)临时变量到底是不是常量? 很多情况下,编译器必须建立临时对象。像其他任何对象一样,它们需要存储空间而且必须被构造和删除。区别是我们从来看不到编译器负责决定它们的去留以及它们存在的细节。对于C++标准草案而言:临时对象自动地成为常量。因为我们通常接触不到临时对象,不能使用与之相关的信息,所以告诉临时对象做一些改变有可能会出错。当然,这与编译器有关,例如:vc6、vc7都对此作了扩展,所以,用临时对象做左值,编译器并没有报错。 (10)与static搭配会不会有问题? 假设有一个类: class A { public: ...... static void f() const { ......} ...... }; 我们发现编译器会报错,因为在这种情况下static不能够与const共存! 为什么呢?因为static没有this指针,但是const修饰this指针,所以... (11)如何修改常量? 有时候我们却不得不对类内的数据进行修改,但是我们的接口却被声明了const,那该怎么处理呢?我对这个问题的看法如下: 1)标准用法: mutable class A { public: A(int i=0):test(i) { } void SetValue(int i)const { test=i; } private: mutable int test;//这里处理! }; 2)强制转换: const_cast class A { public: A(int i=0):test(i) { } void SetValue(int i)const { const_cast (test)=i; }//这里处理! private: int test; }; 3)灵活的指针: int* class A { public: A(int i=0):test(i) { } void SetValue(int i)const { *test=i; } private: int* test; //这里处理! }; 4)未定义的处理 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { int *p=(int*)&test; *p=i; }//这里处理! private: int test; }; 注意,这里虽然说可以这样修改,但结果是未定义的,避免使用! 5)内部处理:this指针 class A { public: A(int i=0):test(i) { } void SetValue(int i)const { ((A*)this)->test=i; }//这里处理! private: int test; }; 6)最另类的处理:空间布局 class A { public: A(int i=0):test(i),c("a") { } private: char c; const int test; }; int main() { A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);//利用边缘调整 *pi=5;//此处改变了test的值! return 0; } 虽然我给出了6中方法,但是我只是想说明如何更改,但出了第一种用法之外,另外5种用法,我们并不提倡,不要因为我这么写了,你就这么用,否则,我真是要误人子弟了:) (12)最后我们来讨论一下常量对象的动态创建。 既然编译器可以动态初始化常量,就自然可以动态创建,例如: const int* pi=new const int(10); 这里要注意2点: 1)const对象必须被初始化!所以(10)是不能够少的。 2)new返回的指针必须是const类型的。 那么我们可不可以动态创建一个数组呢? 答案是否定的,因为new内置类型的数组,不能被初始化。 这里我们忽视了数组是类类型的,同样对于类内部数组初始化我们也做出了这样的忽视,因为这涉及到数组的问题,我们以后再讨论。 来源:http://zhidao.baidu.com/question/91670015.html?si=32023-07-21 22:54:321
C语言中const有什么用途
const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。const关键字的作用主要有以下几点:(1)可以定义const常量,具有不可变性。 例如: const int Max=100; int Array[Max]; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改; (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。(4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错; 例如: void f(const int i) { i=10;//error! } (5) 为函数重载提供了一个参考。 class A { ...... void f(int i) {......} //一个函数 void f(int i) const {......} //上一个函数的重载 ...... }; (6) 可以节省空间,避免不必要的内存分配。 例如: #define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ...... double i=Pi; //此时为Pi分配内存,以后不再分配! double I=PI; //编译期间进行宏替换,分配内存 double j=Pi; //没有内存分配 double J=PI; //再进行宏替换,又一次分配内存! const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。 (7) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。2023-07-21 22:54:521
函数名前加const是啥意思
是指该函数的返回值是“常量”,不可修改。通常这样的函数返回一个引用(&)或指针。比如:int& abc(...){...}int* xyz(...){...}以后可以这样使用这两个函数:abc(...)=100;*xyz(...)=200;若加上const之后,就限制这样的赋值。2023-07-21 22:55:021
ABB机器人const,pers,var的区别
vVAR Variable,变量。vCONST Constant,常量。vPERS Persistent,可变量。2023-07-21 22:55:123