为了账号安全,请及时绑定邮箱和手机立即绑定

请问以下这些const有什么作用?可以解释一下吗?

请问以下这些const有什么作用?可以解释一下吗?

呼如林 2021-11-25 19:15:33
1.inline const rational operator*(const rational& lhs,const rational& rhs){return rational(lhs.n * rhs.n, lhs.d * rhs.d);}这是一个实现有理数乘积的函数,问“inline const”中的const有什么用?为什么这里要用const呢?2.int comptot()const{return (bsal+yourbonus+allbonus);} 这个const是放在()之后的,这和上面1的放在()之前的有区别么?3.virtual void logTransaction() const=0;这个记得是定义纯虚函数的,不过不理解const=0是什么意思?这个是不是表示函数的返回值是0啊?如果是的话,纯虚函数不是什么都不做的,返回值是0也没意义啊。4.virtual void logTransaction() const;这个const在这里有什么用呢?能去掉么?一楼提供的资料很有用,不过好像找不到对问题1、3解答,希望能完善,如果有高手能针对性的回答一下就最好,视答案还可以加分先肯定一楼回答的价值,不过还未能完全说服我,谢谢!
查看完整描述

2 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

(1)const用于定义常量。

例如:const int N = 100;const int M = 200;
这样程序中只要用到 N、M 就分别代表为整型100、200,N、M 为一常量,在程序中不可改变。
但有人说他编程时从来不用const定义常量。我相信。但他是不懂得真正的编程艺术,用const定义常量不仅能方便我们编程而且能提高程序的清晰性。你是愿意看到程序中100、200 满天飞,还是愿意只看到简单清晰的N、M。相信有没有好处你慢慢体会。
还有人说他不用const定义常量,他用#define宏定义常量。可以。但不知道你有没有发现有时#define宏并没有如你所愿在定义常量。下面我们比较比较const和#define。

1。const定义常量是有数据类型的,而#define宏定义常量却没有。
这样const定义的常量编译器可以对其进行数据静态类型安全检查,而#define宏定义的常量却只是进行简单的字符替换,没有类型安全检查,且有时还会产生边际效应(不如你愿处)。所谓边际效应举例如下:
#define N 100
#define M 200 + N
当程序中使用 M*N 时,原本想要 100 * (200+ N )的却变成了 100 * 200 + N。

2。有些调试程序可对const进行调试,但不对#define进行调试。

3。当定义局部变量时,const作用域仅限于定义局部变量的函数体内。但用#define时其作用域不仅限于定义局部变量的函数体内,而是从定义点到整个程序的结束点。但也可以用#undef取消其定义从而限定其作用域范围。

光用const定义常量,并不能起到其强大的作用。const还可修饰函数形式参数、返回值和类的成员函数等。从而提高函数的健壮性。因为const修饰的东西能受到c/c++的静态类型安全检查机制的强制保护,防止意外的修改。

(2)const修饰函数形式参数

形式参数有输入形式参数和输出形式参数。参数用于输出时不能加const修饰,那样会使函数失去输出功能。因为const修饰的东西是不能改变的。
const只能用于修饰输入参数。
谈const只能用于修饰输入参数之前先谈谈C++函数的三种传递方式。
C++函数的三种传递方式为:值传递、指针传递和引用传递。简单举例说明之,详细说明请参考别的资料。
值传递:
void fun(int x){
x += 5; //修改的只是y在栈中copy x
}
void main(void){
int y = 0;
fun(y);
cout<<"y = "< }
指针传递:
void fun(int *x){
*x += 5;//修改的是指针x指向的内存单元值
}
void main(void){
int y = 0;
fun(&y);
cout<<<<"y = "<}
引用传递:
void fun(int &x){
x += 5;//修改的是x引用的对象值 &x = y;
}
void main(void){
int y = 0;
fun(y);
cout<<<<"y = "<}
看了传递方式后我们继续来谈"const只能用于修饰输入参数"的情况。

当输入参数用"值传递"方式时,我们不需要加const修饰,因为用值传递时,函数将自动用实际参数的拷贝初始化形式参数,当在函数体内改变形式参数时,改变的也只是栈上的拷贝而不是实际参数。
但要注意的是,当输入参数为ADT/UDT(用户自定义类型和抽象数据类型)时,应该将"值传递"改为"const &传递",目的可以提高效率。
例如:
void fun(A a);//效率底。函数体内产生A类型的临时对象用于复制参数 a,但是临时对象的
//构造、复制、析构过程都将消耗时间。
void fun(A const &a);//提高效率。用"引用传递"不需要产生临时对象,省了临时对象的
//构造、复制、析构过程消耗的时间。但光用引用有可能改变a,所以加const

当输入参数用"指针传递"方式时,加const修饰可防止意外修改指针指向的内存单元,起到保护作用。
例如:
void funstrcopy(char *strdest,const char *strsrc)//任何改变strsrc指向的内存单元,
//编译器都将报错
些时保护了指针的内存单元,也可以保护指针本身,防止其地址改变。
例如:
void funstrcopy(char *strdest,const char *const strsrc)

(3)const修饰函数的返回值

如给"指针传递"的函数返回值加const,则返回值不能被直接修改,且该返回值只能被赋值给加const修饰的同类型指针。
例如:
const char *GetChar(void){};
赋值 char *ch = GetChar();//错误const char *ch = GetChar();//正确

(4)const修饰类的成员函数(函数定义体)

任何不会修改数据成员的函数都应用const修饰,这样当不小心修改了数据成员或调用了非const成员函数时,编译器都会报错。
const修饰类的成员函数形式为:int GetCount(void)const;

问题1 属于 const修饰函数的返回值
2 属于 const修饰类的成员函数(函数定义体)
3.4 纯虚函数和虚函数就是这样定义



查看完整回答
反对 回复 2021-11-29
?
翻阅古今

TA贡献1780条经验 获得超5个赞

这是针对性地回答:

1.inline const rational operator*(const
inline const不是一个关键字。
应该是这样的:
inline是内联函数的关键字。就是说这个函数可以在调用时像宏一样扩展代码,节省调用时间。
const rational是一起的,表示返回值类型是rational型的const常量。
我不建议这里是const,返回常量会造成后序操作的很多麻烦。

2.int comptot()const
const放在函数声明或者定义的()后是定义常量函数,表明这个函数不改变实参或者调用对象的值。

3.virtual void logTransaction() const=0;
是定义纯虚函数的,不过又是个断句错误。
virtual void logTransaction() const是一起的,const作用和2一样,表明函数是个常量函数。
=0表示纯虚函数,是针对整个函数声明的,而不是const。

4.virtual void logTransaction() const;
这个const和2一样,就是为了声明常量函数。

常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。因此,定义或说明常类型时必须进行初始化。
一般常量和对象常量

1. 一般常量

一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。如:

int const x=2;



const int x=2;

定义或说明一个常数组可采用如下格式:

<类型说明符> const <数组名>[<大小>]…

或者

const <类型说明符> <数组名>[<大小>]…

例如:

int const a[5]={1, 2, 3, 4, 5};

2. 常对象

常对象是指对象常量,定义格式如下:

<类名> const <对象名>

或者

const <类名> <对象名>

定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。

常指针和常引用

1. 常指针

使用const修饰指针时,由于const的位置不同,而含意不同。下面举两个例子,说明它们的区别。

下面定义的一个指向字符串的常量指针:

char * const prt1 = stringprt1;

其中,ptr1是一个常量指针。因此,下面赋值是非法的。

ptr1 = stringprt2;

而下面的赋值是合法的:

*ptr1 = "m";

因为指针ptr1所指向的变量是可以更新的,不可更新的是常量指针ptr1所指的方向(别的字符串)。

下面定义了一个指向字符串常量的指针:

const * ptr2 = stringprt1;

其中,ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的,而ptr2是可以更新的。因此,

*ptr2 = "x";

是非法的,而:

ptr2 = stringptr2;

是合法的。

所以,在使用const修饰指针时,应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时,const修饰符的位置不同,前者const放在*和指针名之间,后者const放在类型说明符前。

2. 常引用

使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:

const <类型说明符> & <引用名>

例如:

const double & v;

在实际应用中,常指针和常引用往往用来作函数的形参,这样的参数称为常参数。

在C++面向对象的程序设计中,指针和引用使用得较多,其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象,这样,在参数传递过程中就不需要执行拷贝初始化构造函数,这将会改善程序的运行效率。

下面举一例子说明常指针作函数参数的作法。

#include
const int N = 6;
void print(const int *p, int n);

void main()
{
int array[N];
for (int i=0; i cin>>array[i];
print(array, N);
}

void print(const int *p, int n)
{
cout<<"{"<<*p;
for (int i=1; i cout<<","<<*(p+i);
cout<<"}"< }

常成员函数

使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常量或常对象,没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下:

<类型说明符> <函数名> (<参数表>) const;

其中,const是加在函数说明后面的类型修饰符,它是函数类型的一个组成部分,因此,在函数实现部分也要带const关键字。下面举一例子说明常成员函数的特征。

#include
class R
{
public:
R(int r1, int r2) { R1=r1; R2=r2; }
void print();
void print() const;
private:
int R1, R2;
};

void R::print()
{
cout< }

void R::print() const
{
cout< }

void main()
{
R a(5, 4);
a.print();
const R b(20, 52);
b.print();
}

该例子的输出结果为:

5,4
20;52

该程序的类声明了两个成员函数,其类型是不同的(其实就是重载成员函数)。有带const修饰符的成员函数处理const常量,这也体现出函数重载的特点。

常数据成员

类型修饰符const不仅可以说明成员函数,也可以说明数据成员。

由于const类型对象必须被初始化,并且不能更新,因此,在类中说明了const数据成员时,只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。

下面通过一个例子讲述使用成员初始化列表来生成构造函数。

#include
class A
{
public:
A(int i);
void print();
const int &r;
private:
const int a;
static const int b;
};

const int A::b=10;
A::A(int i):a(i), r(a)
{
}

void A::print()
{
cout< }

void main()
{
A a1(100), a2(0);
a1.print();
a2.print();
}

该程序的运行结果为:

100:10:100
0:10:0

在该程序中,说明了如下三个常类型数据成员:

const int & r;

const int a;

static const int b;

其中,r是常int型引用,a是常int型变量,b是静态常int型变量。

程序中对静态数据成员b进行初始化。

值得注意的是构造函数的格式如下所示:

A(int i):a(i),r(a)
{
}

其中,冒号后边是一个数据成员初始化列表,它包含两个初始化项,用逗号进行了分隔,因为数据成员a和r都是常类型的,需要采用初始化格式。



查看完整回答
反对 回复 2021-11-29
  • 2 回答
  • 0 关注
  • 349 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信