zoukankan      html  css  js  c++  java
  • C++在const用法

    注意

    • const对象默觉得文件的局部变量

    全局作用域里定义非const变量时,它在整个程序中都能够訪问。我们能够把一个非const变量定义在一个文件里,如果已经做了合适的声明,就能够在另外的文件里使用这个变量:

    与其它变量不同,除非特别说明。在全局作用域声明的const变量是定义该对象的文件的局部变量。

    此变量仅仅存在于那个文件里,不能被其它文件訪问。通过指定const变量为extern。就能够在整个程序中訪问const对象。

    注意:非const变量默觉得extern。

    要使const变量可以在其它文件里訪问,必须在文件里显式地指定它为extern。


    ------------- const指针、const引用、const引用形參 --------------------

    【1】const修饰指针和引用

    1. 术语“const引用”就是“指向const对象的引用”,习惯说成const引用与非const引用。

    这点与指针不同,指针中“const指针”与“指向const对象的指针”是不同的。

    2. 值得注意的是:const引用和指向const对象的指针二者有一个共同点:const引用既能够指向const对象又能够指向非const对象;指向const对象的指针亦是如此.

    3. 关于const指针与指向const对象的指针,举一个非常easy样例

    1
    2
    3
    4
    5
    6
    int m=1, n=5;
    constint *p1=&m;   //指向const对象的指针:const修饰的是*p1, 即*p1的值是仅仅读的;可是p1这个指针是能够改动的。
    int * const p2=&n; //const指针:const修饰的是p2, 即p2这个指针是仅仅读的;可是*p2的值是能够改动的。
    p1=&n;             //p1的指针改动为变量n的地址,而这个地址就是p2,相当于p1=p2;
    *p2=3;             //*p2的值改动为3。当然*p1的值也就是3
    printf("%d %d ",*p1,*p2);

    【2】形參为const引用的优点

    说到const,就不得不提const引用类型的形參,真正理解了const引用形參的优点,才发现它真是美妙的非常

    简单总结一下。欢迎补充

    a. 当实參的类型比較大时。复制开销非常大(形參初始化时),引用会“避免复制”。

    (这在传递类对象时比較经常使用)

    b. “避免改动实參”。当使用引用时,假设调用者希望仅仅使用实參并不改动实參。则const能够避免使用该引用改动实參

    c. 相比非const引用形參,更具有用性:形參能够使用const对象初始化,可使用字面值或右值表达式的实參来初始化

    以下各给一演示样例

    1
    2
    3
    4
    5
    6
    7
    8
    a. voidsearch(constvector<int> & vec) 避免了实參的复制开销
    b. 同a例。可避免对实參做出改动
    c. 例如以下函数,调用时
    void search(string & s);         调用: search("hello");// Error 实參为字面值常量
    void search(const string & s);   调用: search("hello");// OK
    再如
    void search(int & v);            调用: search(v1+v2);  // Error 实參是一个右值。无法给引用赋值(须要左值)
    void search(const int & v);      调用: search(v1+v2);   // OK

    ---------------const 在类中----------------------------------------

    一般来讲。使用const修饰函数,则函数一定是类成员函数。

    【1】const对象仅仅能调用const成员函数 非const对象能够调用const成员函数

    解释:不能将指向const对象的指针赋值给非const对象指针,而同意将非const对象指针赋值给指向const对象的指针。

    为什么这样解释?这源自于调用成员函数时发生的事情:

    调用成员函数时会发生的事情:将调用对象与函数绑定,即将成员函数隐含的形參this初始化为调用对象的地址。

    因此,const对象传递的实參地址为const class * const this。而非const成员函数被调用时还是使用了class *const this的形參接收,结果就是把指向const对象的指针赋给非const对象的指针,这是不同意的。所以const对象仅仅能调用const成员函数。后者同理,非const对象在调用const成员函数时实质上是将非const对象的指针(实參)赋值给了const对象指针(形參),而这又是能够的。故非const对象能够调用const成员函数。

    【2】const成员变量不能被改动,且必须在初始化列表中赋值。

    const成员函数不能改变成员变量, 且不能调用非const成员函数(即不可有改变值的企图)

    相反,非const成员函数当然能够调用const成员函数

    【3】const成员函数的返回值:值类型 & const引用类型  (不可返回非const引用)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    example.
    classVec
    {
    private:
        vector<string> textVec;
    public:
        conststring & text_line(size_tlineNum) const
        {
            returntextVec.at(lineNum-1);
        }
    };

    假设成员函数为const,则对象调用该常函数传递this时已经变成了const对象,假设函数写成例如以下形式

    1
    2
    3
    4
    string & text_line(size_tlineNum) const
    {
        returntextVec.at(lineNum-1);
    }

    则编译会报错:不能将const string 转化为 string &,由于此时相当于将一个非const引用指向了一个const类型变量。故要返回引用就必须是const引用。

    ------------返回值类型---

    当然还有其它的写法,即让函数返回值为值类型,即

    1
    2
    3
    4
    string text_line(size_tlineNum) const
    {
        returntextVec.at(lineNum-1);
    }

    此时实际上是做了一个内存拷贝,由于string是类类型,有人会问,那这样不是相当于一个const对象赋值给非const对象吗?

    对于上述函数,实际是调用了string的拷贝构造,并且拷贝构造的參数便是const string类型。这里又涉及到const类型作參数的问题。上面已讲

    对于函数的返回值为值类型,无非就两种,一种是普通的内置类型。进行赋值操作;一种是类类型,调用拷贝构造进行内存拷贝。例如以下:

    1
    2
    3
    4
    constint a = 9;
    int b = a;   (int &bb = a; // error)  // 赋值
    constset<int> s;
    set<int> ss = s;  // 内存拷贝

    所以我们要注意:

    不能够将const对象指针或引用赋值给非const对象的指针和引用。可是能够将const对象初始化给非const对象;

    const与非const在对象层次(not引用或指针层次)上的互相赋值是同意的。可逆的;就像

    1
    2
    3
    constint a = 9;
    int aa = a;
    constint aaa = aa;

    -------------------const与重载---------------------------------------

    基于const重载的情况有两种,一种是基于函数形參类型是否为const的重载;一种是基于类成员函数是否为const的重载

    【1】   基于函数形參类型是否为const的重载

    当且仅当形參为引用或指针类型时。形參是否为const才有影响

    -----引用类型----

    可基于函数的引用形參是指向const对象还是指向非const对象,实现重载,示比例如以下:

    1
    2
    3
    4
    5
    6
    A: voidsearch(Student &);
    B: voidsearch(constStudent &);
    constStudent a;
    Student b;
    search(a);  // 调用B
    search(b);  // 调用A

    注:依据上面讲的我们知道,假设形參是普通引用,则不能将const对象传递给该形參。

    假设传递的是非const对象。按上面提到的,这两种函数都是可行的,由于非const对象既可用于初始化const引用,也可初始化非const引用。那么没有二义性么?

    这就是编译器在调用函数时遵循的原则首先是“精确匹配”,我们知道,将const引用初始化为非const对象须要隐式转换的。所以不符合精确匹配,故调用A。

    -----指针类型----

    基于指针形參的const重载与引用是一样的。

    仅仅是有一个问题要注意:

    上面术语说到const引用就是指向const对象的引用,指针则差别于const指针和指向const对象的指针。

    所以要注意:不能基于指针本身是否为const来重载函数

    1
    2
    3
    4
    void search(int * ptr);
    void search(int * const ptr);
    // 这不能实现重载,指针本身是否const并不会带来差别
    // 在函数调用时,形參都复制了指针的值

    【2】   基于类成员函数是否为const的重载

    在类中,基于成员函数是否为const,可重载一个成员函数,例如以下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    classVec
    {
    private:
        vector<string> textVec;
    public:
        conststring & text_line(size_tlineNum) const
        {
            returntextVec.at(lineNum-1);
        }
        string & text_line(size_tlineNum)
        {
            returntextVec.at(lineNum-1);
        }
    };

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    MySQL8 Keepalived+双主
    Last_SQL_Errno: 1050 Last_SQL_Error: Error 'Table 'events' already exists' on query. Default database: 'eygle'. Query: 'create table events
    [MY-011522] [Repl] Plugin group_replication reported: 'The member contains transactions not present in the group.
    MYSQL8 裸机搭主从
    MY-011292 MY-011300 MY-013597 MY-011300
    RHLE8 docker安装
    docker harbor x509: certificate signed by unknown authority action: push: unauthorized to access repository
    harbor配置https访问
    action: push: unauthorized to access repository
    unlock DDIC for HANADB
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4655077.html
Copyright © 2011-2022 走看看