[转载] static 和 const的解释(二)

本文详细解析了C++中const成员函数的概念及其作用。强调了const关键字在成员函数中的重要性,即确保函数不会修改类的数据成员,并讨论了如何正确地在函数声明和定义中使用const。

http://bbs.chinaunix.net/viewthread.php?tid=143183

 

static 和 const的解释

QUOTE:
原帖由 "yuxq" 发表:
...
5. const 限定类的成员函数:

class classname {
 public:
  int fun() const;
 .....
}

  注意:采用此种const 后置的形式是一种规定,亦为了不引起混淆。在此函数的声明中和定义中均要使用const,因为const已经成为类型信息的一部分。

获得能力:可以操作常量对象。

失去能力:不能修改类的数据成员,不能在函数中调用其他不是const的函数。



楼主的这篇文章值得仔细阅读。但是,我觉得上述“const 限定类的成员函数”这一部分写得比较简略,特别是其中“注意”后面的文字,更是使人不知所云,所以想对这一部分做一些补充说明。

类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变。在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加 const,而对于改变数据成员的成员函数不能加 const。所以 const 关键字对成员函数的行为作了更加明确的限定:有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员;没有 const 修饰的成员函数,对数据成员则是可读可写的。除此之外,在类的成员函数后面加 const 还有什么好处呢?楼主告诉我们的:“获得能力:可以操作常量对象”,其实应该是常量(即 const)对象可以调用 const 成员函数,而不能调用非const修饰的函数。正如非const类型的数据可以给const类型的变量赋值一样,反之则不成立。

请看下面一个完整的例子,然后我再作一些说明。
#include <iostream>;
#include <string>;
using namespace std;

class Student {
public:
Student() {}
Student( const string& nm, int sc = 0 )
: name( nm ), score( sc ) {}

void set_student( const string& nm, int sc = 0 )
{
name = nm;
score = sc;
}

const string& get_name() const
{
return name;
}

int get_score() const
{
return score;
}

private:
string name;
int score;
};

// output student's name and score
void output_student( const Student& student )
{
cout << student.get_name() << "\t";
cout << student.get_score() << endl;
}

int main()
{
Student stu( "Wang", 85 );
output_student( stu );
}
复制代码


设计了一个类 Student,数据成员有 name 和 score,有两个构造函数,有一个设置成员数据函数 set_student(),各有一个取得 name 和 score 的函数 get_name() 和 get_score()。请注意 get_name() 和 get_score() 后面都加了 const,而 set_student() 后面没有(也不能有const)。

首先说一点题外话,为什么 get_name() 前面也加 const。如果没有前后两个 const 的话,get_name() 返回的是对私有数据成员 name 的引用,所以通过这个引用可以改变私有成员 name 的值,如
Student stu( "Wang", 85 );
stu.get_name() = "Li";
复制代码

即把 name 由原来的 "Wang" 变成了 "Li",而这不是我们希望的发生的。所以在 get_name() 前面加 const 避免这种情况的发生。

那么,get_name() 和 get_score() 这两个后面应该加 const的成员函数,如果没有 const 修饰的话可不可以呢?回答是可以!但是这样做的代价是:const对象将不能再调用这两个非const成员函数了。如
const string& get_name(); // 这两个函数都应该设成 const 型
int get_score();
void output_student( const Student& student )
{
cout << student.get_name() << "\t"; // 如果 get_name() 和 get_score() 是非const成员函数,这一句和下一句调用是错误的
cout << student.get_score() << endl;
}
复制代码

由于参数student表示的是一个对const Student型对象的引用,所以 student 不能调用非const成员函数如 set_student()。如果 get_name() 和 get_score() 成员函数也变成非const型,那么上面的 student.get_name() 和 student.get_score() 的使用就是非法的,这样就会给我们处理问题造成困难。

因此,我们没有理由反对使用const,该加const时就应该加上const,这样使成员函数除了非const的对象之外,const对象也能够调用它。

#include <unistd.h> #include <signal.h> #include "libubus.h" static struct ubus_context *ctx; static struct blob_buf b; enum { REQ_STATION_COUNT, REQ_AP_NAME, __REQ_MAX }; /* 接收的解析格式, client发送过来的调用是 blobmsg_add_u32(&b, "getcnt", ap_index); */ static const struct blobmsg_policy fun2_message_parse_policy[__REQ_MAX] = { [REQ_STATION_COUNT] = { .name = "getcnt", .type = BLOBMSG_TYPE_INT32 }, [REQ_STATION_COUNT] = { .name = "apname", .type = BLOBMSG_TYPE_STRING }, }; static int fun2_handler(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { struct blob_attr *tb[__REQ_MAX]; //模拟ap数组中station的个数 int ap_array[] = {-1, 11111,22222,33333}; int ap_index; blobmsg_parse(fun2_message_parse_policy, __REQ_MAX, tb, blob_data(msg), blob_len(msg)); if (!tb[REQ_STATION_COUNT]) return UBUS_STATUS_INVALID_ARGUMENT; ap_index = blobmsg_get_u32(tb[REQ_STATION_COUNT]); fprintf(stdout, "someone ask the ap[%d]' info \n", ap_index); if (ap_index > (sizeof(ap_array) / sizeof(int))) ap_index = 0; blob_buf_init(&b, 0); //返回客户端请求的station个数 blobmsg_add_u32(&b, "stacnt", ap_array[ap_index]); //发送 ubus_send_reply(ctx, req, b.head); return 0; } static const struct ubus_method test_methods[] = { UBUS_METHOD("fun2", fun2_handler, fun2_message_parse_policy), }; static struct ubus_object_type test_object_type = UBUS_OBJECT_TYPE("server_fun", test_methods); //定义一个ubus 对象。 //其他进程通过调用相应字符串给执行对应的回调函数 //注册成功后可以通过命令ubus list -v 查看到obj //' server_fun' @79a8beac // "fun2" : {"getcnt":"Iterger","apname":"String"} static struct ubus_object test_object = { .name = "server_fun", .type = &test_object_type, .methods = test_methods, .n_methods = ARRAY_SIZE(test_methods), }; static void server_main(void) { int ret; //向ubusd新增一个对象,之后test_object在ubusd中有一个id号,其他进程通过该id号来向test_object发送消息。 ret = ubus_add_object(ctx, &test_object); if (ret) fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret)); uloop_run(); } int main(int argc, char **argv) { const char *ubus_socket = NULL; int ch; while ((ch = getopt(argc, argv, "cs:")) != -1) { switch (ch) { case 's': ubus_socket = optarg; break; default: break; } } argc -= optind; argv += optind; uloop_init(); signal(SIGPIPE, SIG_IGN); ctx = ubus_connect(ubus_socket); if (!ctx) { fprintf(stderr, "Failed to connect to ubus\n"); return -1; } ubus_add_uloop(ctx); server_main(); ubus_free(ctx); uloop_done(); return 0; } ———————————————— 版权声明:本文为优快云博主「东升」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.youkuaiyun.com/liangdsing/article/details/53694495
09-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值