[转载]Const用法小结

Java 正则表达式 正则表达式中存在一些预定义字符,它们可以匹配特定的字符集合。\d:匹配任意数字字符,相当于字符类[0-9]。\D:匹配任意非数字字符,相当于字符类[^0-9]。\s:匹配任意空白字符,包括空格、制表符、换页符等,相当于字符类[f \r\t\v]。\S:匹配任意非空白字符,相当于字符类。w:匹配任意字母、数字或下划线字符,相当于字符类。\W:匹配任意非字母、数字或下划线的字符,相当于字符类。:通常用于匹配除换行符之外的任意单个字符。但在一些情况下,它可以配置为匹配包括换行符在内的任意字符。 阅读详情
关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,参考了康建东兄的const使用详解一文,对其中进行了一些补充,写下了本文。



1.     const常量,如const int max = 100;
优点:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应)

2.     const 修饰类的数据成员。如:
class A

{

  const int size;

  …

}

const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。如

class A

{

const int size = 100;   //错误

int array[size];       //错误,未知的size

}

const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。如

class A

{…

enum {size1=100, size2 = 200 };

int array1[size1];

int array2[size2];

}

枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

3.     const修饰指针的情况,见下式:

int b = 500;
const int* a = &       [1]
int const *a = &       [2]
int* const a = &       [3]
const int* const a = &   [4]

如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。

4.   const的初始化

先看一下const变量初始化的情况
1) 非指针const常量初始化的情况:A b;
const A a = b;

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

A* d = new A();
const A* c = d;
或者:const A* c = new A();
3)引用const常量初始化的情况:
A f;
const A& e = f;     // 这样作e只能访问声明为const的函数,而不能访问一        

般的成员函数;

  [思考1]: 以下的这种赋值方法正确吗?
  const A* c=new A();
  A* e = c;
  [思考2]: 以下的这种赋值方法正确吗?
  A* const c = new A();
  A* b = c;

5.   另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法:A& operator=(const A& a);
void fun0(const A* a );
void fun1( ) const; // fun1( ) 为类成员函数
const A fun2( );

1) 修饰参数的const,如 void fun0(const A* a ); void fun1(const A& a);
调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
[注意]:参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。

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

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

2) 修饰返回值的const,如const A fun2( ); const A* fun3( );
这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}

返回值用const修饰可以防止允许这样的操作发生:Rational a,b;
Radional c;
(a*b) = c;

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

1.   一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。

2.     如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。如:

const char * GetString(void);

如下语句将出现编译错误:

char *str=GetString();

正确的用法是:

const char *str=GetString();

3.   函数返回值采用“引用传递”的场合不多,这种方式一般只出现在类的赙值函数中,目的是为了实现链式表达。如:

class A

{…

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 A& operator=(const A& a);

6.   类成员函数中const的使用
一般放在函数体后,形如:void fun() const;
任何不会修改数据成员的函数都因该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将报错,这大大提高了程序的健壮性。如:

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;

}

7.     使用const的一些建议

1 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4 const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5 不要轻易的将函数的返回值类型定为const;
6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

[思考题答案]
1 这种方法不正确,因为声明指针的目的是为了对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确;
2 这种方法正确,因为声明指针所指向的内容可变;
3 这种做法不正确;
在const A::operator=(const A& a)中,参数列表中的const的用法正确,而当这样连续赋值的时侯,问题就出现了:
A a,b,c:
(a=b)=c;
因为a.operator=(b)的返回值是对a的const引用,不能再将c赋值给const常量
java正侧表达式合(group)使用 因为这个例子中没有使用命名,所以调用Matcher.group("firstName"), Matcher.group("lastName"), Matcher.group("phone") 返回的都是null。 来定义的, 例如"(?\w+)\s.方法获取的命名的值分别是"John"、"Smith"、"123-456-7890"。命名有助于使正则表达式更具可读性,并且可以让你更容易地访问捕获的值。 阅读详情

相关推荐

正则表达式 \b \B,单词边界的匹配

正则表达式 \b \B 深入浅出理解单词边界的匹配

记录学习点滴 8693

Java正则入门(1)——去除字符串头尾空格

在其他语言中,\\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。 在 Java 中,\\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。 所以,在其他的语言中(如Perl),一个反斜杠 \ 就足以具有转义的作用,而在 Java正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表...

折腾怪的博客 3229

java正则表达式合并_java – 合并两个正则表达式

您可以在多个Regex之间使用Pipe(|)来匹配所有这些: –String s = "name lastname (username) ; name lastname(username) ; name lastname(username) ;";// Matches (?<=\\()[^\\)]+ or ((?<=]+)Pattern pattern = Pattern.comp...

weixin_36278243的博客 1938

学习正则表达式 - 边界

零宽断言、行的开始和结束、dotall 模式、单词边界和非单词边界、主题词的起始与结束位置、使用元字符的字面值、在段首加标签等

wzy0623的专栏 2502

解决中文标题比如第一百零五章或数字标题第001章的排序问题

近期在作一个阅读app的时候,碰到了要对中文标题还有数字标题排序问题,经过一番搜索与实践,终于达成了目的。 工具类 StringUtils package cn.wq.elf.utils; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; public class...

wqbs369的专栏 487

java 正则表达式总结

java 正则表达式 内容分享。

CSDN / 稀土掘金/ B站 / GitHub: Cyan_RA9 1万+

Java正则表达式概念-yellowcong

Java正则的使用在正则使用的时候,需要都用()来将正则表达式括起来分,比如([\\w]+.)([\\w]*\\.[\\w]*),才可以使用这个数据,不然,就不可以使用这个东西了

1697

正则表达式(七)——边界匹配

package com.wy.regular; public class RegularTest { public static void main(String[] args) { /* * 边界匹配 boundary 指的是开头和结尾 * ^在中括号[]中的第一个字符是取反,在[]外边代表的是输入的开头 * $是一行的结尾 * \b 代表的是一个单词的边界(...

stujike123456的博客 4251

java中使用正则表达式中的

是括号划分的正则表达式

huangjhai的博客 1238

java 正则_Java正则表达式

我们可以通过括号将多个字符合为一个单位。例如,(ab)。正则表达式中的每个都有一个号,从1开始。Matcher类中的方法groupCount()返回与Matcher实例相关联的模式中的数。0引用整个正则表达式和不由groupCount()方法报告。正则表达式中的每个左括号标记新的开始。我们可以在正则表达式中返回引用号。假设我们要匹配以“abc"开头,后跟“xyz"的文本,后跟“abc...

weixin_39908082的博客 177

JAVA里合并多个不相关正则表达式在一起的代码例子

事情的来源是,我要得到某个字符串里满足条件的一部分,但这个条件有多个可能性,比如(.+?)之间的我需要(.+?)之间的我也需要(.*?) 这个之间的我也需要当然其它的可以是任何符合我要求的正则表达式,我的需求就是不想用多个正则分别匹配,然后装,而是希望在一个正则里面实现。当然这几个正则之间肯定是或的关系,只要一段字符串满足任何一个正

老紫竹的专栏 8324

Python 正则表达式进阶用法:边界匹配

边界匹配是指通过正则表达式边界符号来匹配字符串中的特定位置,而不是字符本身。\b:单词边界,匹配单词的开头或结尾。\B:非单词边界,匹配不是单词边界的位置。:匹配字符串的开始位置。:匹配字符串的结束位置。通过使用这些边界匹配符,我们可以实现更加精确的匹配,从而避免匹配到不需要的字符或位置。边界匹配是 Python 正则表达式中非常有用的一种技巧。它允许我们精确地控制匹配的范围,避免匹配到不需要的部分。通过使用\b\B和,我们可以在不同的场景中应用正则表达式进行更细粒度的文本处理。\b。

chusheng1840的博客 1646

Java正则表达式中的分()

使用replaceAll方法,如果匹配到满足正则表达式的子串,就会将其替换为满足正则表达式的子串的第一个字符,这是由于这里使用$号,引用了正则表达式中第一捕获的内容。这种分主要用于控制匹配的逻辑,但不需要提取其内容,分之后不需要在使用本数据,仅仅只是把数据括起来,不占用号。在正则表达式中经常见到()符号,这个符号就是分正则表达式中的分用于将一个模式的一部分分开,以便在匹配时进行更灵活的操作。捕获分就是把这一的数据捕获出来,在用一次,可用于匹配重复的内容,捕获分使用()来进行分

2301_78141450的博客 737

Java正则表达式(regex)匹配多行(Pattern.MULTILINE和Pattern.DOTALL模式)

转载 https://www.cjavapy.com/article/68/

qq769298218的博客 1025

正则表达式5____单词边界和字符串边界

位置匹配 在使用正则表达式时,如果只需要对某段文本里的特定位置进行匹配,通过位置匹配可以解决这个问题,也就是使用边界限定符,在正则表达式里用一些特殊的元字符来表明想让匹配操作在什么位置发生 一 单词边界 1. 由限定符\b指定的单词边界 (b 指 boundary边界), \b用来匹配一个单词的开始或结尾 一个示例 The cat scattered his food all

daozhongyang的专栏 6683

STLG_11_05_正则表达式 - 边界匹配

正则表达式中的边界匹配用于指定匹配的起始或结束位置,确保模式匹配的准确性。例如,^表示行首,$表示行尾,\b表示单词边界。通过边界匹配,可以精确控制匹配范围,避免不必要的误匹配。比如,使用^abc确保只匹配以“abc”开头的行,而\bword\b则匹配独立的单词“word”。边界匹配是实现精准文本处理的重要工具,广泛应用于文本搜索和验证场景。

cdlislxjt的博客 787

正则表示边界

表示边界 字符 功能 ^ 匹配字符串开头 $ 匹配字符串结尾 \b 匹配一个单词的边界 \B 匹配非单词边界 示例1:$ 需求:匹配163.com的邮箱地址 #coding=utf-8 import re # 正确的地址 ret = re.match("[\w]{4,20}@163\.com", "xiaoWang@163.com") ret.group() ...

xiao-啸 249
上一篇: [转载]Shell脚本初学者的入门知识
下一篇: C++中的虚函数(virtual function)
csdboy
博客等级 码龄25年 0粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值