const char* & NOT char* const &

本文详细解析了C++中const引用的概念及其在模板类中的应用,澄清了一个关于模板特化过程中的常见误解,并通过具体示例展示了const char* & 和 char* const & 的区别。

原文:http://blog.youkuaiyun.com/ftofficer/article/details/261193


今天在BBS VC版上看到有个同学这么一个帖子,说VC在编译模板时有BUG,他贴的测试代码如下:

// TemplateBug.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
 
// 先定义一个接口
template < class DataType >
class A
{
public:
    virtual int SomeFunc(const DataType &Value ) = 0;
};
 
// B来实现这个接口为这样,竟然编译不过!
template< class something1, class something2 >
class B : public A< char* >
{
public:
    virtual int SomeFunc( const char* &Value ) { return 0; };
};
 
// 改成这样编译才能通过
template< class something1, class something2 >
class C : public A < char* >
{
public:
    virtual int SomeFunc( char* const &Value ) { return 0; };
};
 
// const char* 和 char* const 的含义是大不一样的,可是经过模板的参数化过程
// 后,混淆了两者,这应该算个BUG了吧?
 
int _tmain(int argc, _TCHAR* argv[])
{
    B< int, int > b; // 注释此行后编译通过
    C< int, int > c;
    return 0;
}

其中那段注释很有意思,但是这个不是bug,相反,应该说这样才是符合C++规范的,
不是编译器混淆了两者,而是我们的作者混淆了两者。
再来看const char* &p 和 char* const &p 两种引用:
两者都是对一个对象的引用。
但是前者的“这个对象”是 const char*,一个指向 const char 的指针,注意!虽
然这个指针指向的char不可以改变,但这个指针本身的值是可以改变的,也就是说,
他可以被改变而指向另一个 const char 对象。
后者的“这个对象”则是char*, 一个指向char的指针。这个指针指向的东西是可以
改变的,但是这个指针本身是不能改变的,你不能让他指向另一个char对象。
如果你觉着这段表述不够清晰,请自行编译一下下面这段代码:
void fconst( const char* & p ) {
    *p = 'L';       // error C2166: l 值指定常数对象
    p ++;           // OK!
}
void constf( char* const & p ) {
    *p = 'L';       // OK!
    p ++ ;          // error C2166: l 值指定常数对象
}
int main () {
    char str[] = "Hello world";
    char* p = &str[2];
    fconst(p);
    constf(p);
}
现在const char *& 与 char* const& 的区别已经清楚了,那么我们看模板如何特化的
作者的SomeFunc的参数是一个DataType的const reference,所谓的const reference,
是说你不能再改变这个reference所引用的对象的状态,因此 const DataType & 和
DataType const &是等价的,也就是说, template A<DataType> 的函数SomeFunc
的参数是一个对某个对象的常引用,这个引用所引用的对象的状态在函数作用域内不
可以被改变。
那么很明确吧,A< char* > 被特化作为 class B 和 C 的基类,那么它的纯虚成员函数
SomeFunc的参数就被特化为对于char* 的const reference了,SomeFunc也就具有形式
int SomeFunc( char* const& ),因此如果定义成int SomeFunc(const char* &Value)
不会与纯虚函数匹配,自然变成的普通的虚函数,而纯虚函数没有定义:
error C2259: “B<something1,something2>” : 不能实例化抽象类
        with
        [
            something1=int,
            something2=int
        ]
        由于下列成员:
        “int A<DataType>::SomeFunc(const DataType & )” : 未定义纯虚函数
        with
        [
            DataType=char *
        ]
        tempBUG.cpp(5) : 参见“A<DataType>::SomeFunc”的声明
        with
        [
            DataType=char *
        ]
所谓的BUG也就不攻自破。呵呵。


你给出的两个变量: ```c const char *username, const char *password ``` 是两个**指向常量字符的指针**,它们通常用于表示**字符串常量**,例如用户名和密码。我们来详细解释这两个变量的含义、作用以及使用场景。 --- ## ✅ 1. `const char *username` 是什么意思? 这是一个**指向常量字符的指针(pointer to const char**,表示: - `username` 是一个指针,它指向一个字符(char)。 - 由于前面加了 `const`,所以**指针所指向的内容是不可修改的**。 - 你可以让指针指向不同的地址(即指向不同的字符串),但不能通过这个指针修改字符串内容。 ### 示例: ```c const char *username = &quot;admin&quot;; printf(&quot;%s\n&quot;, username); // 输出:admin // username[0] = &#39;A&#39;; // 错误:不能修改常量字符串 username = &quot;newuser&quot;; // 合法:可以改变指针指向 ``` --- ## ✅ 2. `const char *password` 同理 ```c const char *password = &quot;123456&quot;; printf(&quot;%s\n&quot;, password); // 输出:123456 // password[0] = &#39;x&#39;; // 错误 password = &quot;newpass&quot;; // 合法 ``` --- ## ✅ 3. 为什么使用 `const char *`? 在函数参数或变量中使用 `const char *` 有以下优点: | 优点 | 说明 | |------|------| | **安全性** | 防止函数意外修改传入的字符串内容 | | **可读性** | 明确表示该字符串是只读的 | | **兼容性** | 可以接受字符串字面量(如 `&quot;hello&quot;`),而非常量指针则不行 | | **优化** | 编译器可以对常量字符串进行优化,例如放入只读内存段 | --- ## ✅ 4. 常见使用场景 ### 场景一:函数参数中使用 ```c void login(const char *username, const char *password) { printf(&quot;Username: %s\n&quot;, username); printf(&quot;Password: %s\n&quot;, password); // 不会修改用户名和密码 } ``` ### 场景二:主函数中传参 ```c int main() { const char *username = &quot;admin&quot;; const char *password = &quot;secret&quot;; login(username, password); return 0; } ``` ### 场景三:字符串常量池中使用 ```c const char *greetings[] = { &quot;Hello, admin!&quot;, &quot;Welcome back.&quot;, &quot;Invalid username or password.&quot; }; ``` --- ## ✅ 5. 注意事项 - `const char *` 指向的内容不可修改,但指针本身可以指向别的字符串。 - 字符串字面量如 `&quot;admin&quot;` 是存储在**只读内存区域**中的,试图修改会引发**未定义行为**。 - 如果你确实需要修改字符串内容,请使用字符数组: ```c char password[] = &quot;123456&quot;; // 可以修改 password[0] = &#39;x&#39;; // 合法 ``` --- ## ✅ 示例代码:完整演示 ```c #include &lt;stdio.h&gt; void login(const char *username, const char *password) { printf(&quot;Logging in with:\n&quot;); printf(&quot;Username: %s\n&quot;, username); printf(&quot;Password: %s\n&quot;, password); } int main() { const char *user = &quot;admin&quot;; const char *pass = &quot;123456&quot;; login(user, pass); // user = &quot;newuser&quot;; // 合法 // pass[0] = &#39;x&#39;; // 非法:不能修改 const 字符串 return 0; } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值