const的用法,特别是用在函数前面与后面的区别!

const的用法,特别是用在函数前面与后面的区别!


const的用法,特别是用在函数后面

在普通的非 const成员函数中,this的类型是一个指向类类型的 const指针。可以改变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修饰即可,因此函数最终成为voidFunc(const A &a)

以此类推,是否应将void Func(int x) 改写为voidFunc(const int&x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。

问题是如此的缠绵,我只好将“const&”修饰输入参数的用法总结一下。

对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const引用传递”,目的是提高效率。例如将voidFunc(A a) 改为voidFunc(const A &a)。

对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如voidFunc(int x) 不应该改为voidFunc(const int &x)。

2.用const修饰函数的返回值

如果给以“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同类型指针。例如函数
const char * GetString(void);
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char  *str =GetString();
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值。
例如不要把函数int GetInt(void) 写成constint GetInt(void)。
同理不要把函数AGetA(void) 写成constA GetA(void),其中A为用户自定义的数据类型。
如果返回值不是内部数据类型,将函数AGetA(void) 改写为constA &GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。例如:

 

classA
{
    A & operate = (const A &other); // 赋值函数
};
A  a, b, c; // a, b, c 为A的对象
 
a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法


如果将赋值函数的返回值加const修饰,那么该返回值的内容不允许被改动。上例中,语句a= b = c 仍然正确,但是语句(a= b) = c 则是非法的。


3 . const 成员函数


      任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性。以下程序中,类stack的成员函数GetCount仅用于计数,从逻辑上讲GetCount应当为const函数。编译器将指出GetCount函数中的错误。

 
class Stack
{
 public:
    void Push(int elem);
    int Pop(void);
    int GetCount(void) const; // const 成员函数
 private:
    int m_num;
    int m_data[100];
};
int Stack::GetCount(void) const
{
    ++ m_num; // 编译错误,企图修改数据成员m_num
    Pop();// 编译错误,企图调用非const函数
    return    m_num;
}

 


const 成员函数的声明看起来怪怪的:const关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。
关于Const函数的几点规则:

  • const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
  • const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
  • const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
  • 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的
  •  
补充:
标题:const放在后面有什么意思?
--------------------------------------------------------------------------------
一个函数
AcGePoint3dstartPoint() const;
const放在后面跟前面有区别么
==>
准确的说const是修饰this指向的对象的
譬如,我们定义了
classA
{
public:
    f(int);
};

 

这里f函数其实有两个参数,第一个是A*const this, 另一个才是int类型的参数
如果我们不想f函数改变参数的值,可以把函数原型改为f(const int),但如果我们不允许f改变this指向的对象呢?因为this是隐含参数,const没法直接修饰它,就加在函数的后面了,表示this的类型是const A *const this。
const修饰*this是本质,至于说“表示该成员函数不会修改类的数据。否则会编译报错”之类的说法只是一个现象,根源就是因为*this是const类型的

 

C++中const在 函数后面

一、概念

  当const在函数名前面的时候修饰的是函数返回值,在函数名后面表示是常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。

二、原理:

  我们都知道在调用成员函数的时候编译器会将对象自身的地址作为隐藏参数传递给函数,在const成员函数中,既不能改变this所指向的对象,也不能改变this所保存的地址,this的类型是一个指向const类型对象的const指针。

具体示例:

一个函数名字后有const,这个函数必定是成员函数,也就是说普通函数后面不能有const修饰,如:int print( ) const {.......} 这个函数必定为成员函数,即在类里面定义的函数。

    在一个类里定义了一个const成员函数后,则此函数不能修改类中的成员变量,如果定义了一个类的const对象(非const对象可以调用const成员函数和非const成员hanshu ),它只能调用类中的const成员函数,如:

class text{

        public:

               void print_const(void) const   { cout<<"hello"<<endl;}          //有const修饰

              void print(void) {cout<<"hello"<<endl;}            //没有const修饰

             void getk(void)  const  {k=5; }          //错误,有const修饰,不能修改k的值,

      private:

             int k;

};

const text a;

int main()

{
     a.print();           //错误,const对象只能调用
     a.printf_const();   //正确
}

// void print() const {}  和 void print() {}   是重载函数,假如对象为const,则调用void print () const成员函数,如果为非const,则调用void print() ;

class text{
public:
 void print(void) const {cout<<"hello_const"<<endl;}
 void print(void) {cout<<"hello"<<endl;}

};

const text a;      
int main()
{
   a.print();    //屏幕输出 hello_const  假如对象a 定义为 text a,则输出 hello
   return 0;
}

具有类型 的表达式会丢失一些 const-volatile 限定符以调用

 xutility(893): error C3848: 具有类型“const rule”的表达式会丢失一些 const-volatile 限定符以调用“bool rule::operator ()(const Node &,const Node &)”

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <deque>
#include <ctime>
#include <list>
#include <set>
using namespace std;

//指定set排序规则 从大到小
//仿函数
class myCompare {
public:
	//重载()
	bool operator()(int v1, int v2){
		return v1 > v2;
	}
};

void test() {
	//从大到小排序,在插入前就指定排序规则
	set<int, myCompare>s;
	s.insert(5);
	s.insert(1);
	 
	for (set<int, myCompare>::iterator it = s.begin(); it != s.end(); ++it) {
		cout << *it << " ";
	}
}

int main(){
	test();
	return 0;
}

VS 编译函数必须加 const

class myCompare {
public:
    //重载()
    bool operator()(int v1, int v2) const{
        return v1 > v2;
    }
};

原因:怀疑是 VS 要求这个函数只能实现比较的功能,不允许修改类的成员;

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
在 C++ 中,const 关键字用于指定变量或函数的常量性,即表示该变量或函数的值或返回值不能被修改。 1. 常量变量 声明一个常量变量需要在变量类型前面加上 const 关键字。例如: ```cpp const int MAX_NUM = 100; ``` 这里定义了一个常量 MAX_NUM,它的值为 100,不能被修改。如果试图修改 MAX_NUM 的值,会导致编译错误。 2. 常量指针 声明一个指向常量的指针需要在变量类型前面加上 const 关键字。例如: ```cpp const int* p = &MAX_NUM; ``` 这里定义了一个指向常量的指针 p,p 指向 MAX_NUM,但是不能通过 p 修改 MAX_NUM 的值。如果试图修改 p 指向的值,也会导致编译错误。 3. 指针常量 声明一个常量指针需要在指针变量前面加上 const 关键字。例如: ```cpp int num = 10; int* const p = &num; ``` 这里定义了一个常量指针 p,p 指向 num,但是 p 的值不能被修改。也就是说,p 不能指向其他的内存地址。如果试图修改 p 的值,也会导致编译错误。 4. 常量成员函数 在类中声明一个成员函数为常量成员函数,需要在函数声明后面加上 const 关键字。例如: ```cpp class MyClass { public: void func() const; }; ``` 这里声明了一个常量成员函数 func(),在该函数中不能修改成员变量的值。常量成员函数可以被常量对象和非常量对象调用,但是非常量对象不能调用常量成员函数以外的成员函数。 总之,const 关键字用于指定变量或函数的常量性,可以有效地防止程序中的错误修改,提高程序的可靠性和安全性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恋恋西风

up up up

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值