• c++学习笔记:类的若干基础问题


    1. 为什么需要在类定义后面’}'后面加分号

    c++的class定义后面可以接一个对象定义列表,当然这并不是一个很好的编程习惯,但c++是支持的.

    001
    002
    003
    class B{
        //成员变量和函数
    }b1,b2;

    这个定义了类B,以及B的两个对象b1和b2.

    2. 对象的初始化

    如果没有给类定义构造函数,c++编译器会自动生成一个构造函数去初始化这些值,比如string成员会初始化为空字符串.

    构造函数中的初始化列表是初始化阶段运行,而构造函数中的语句,则属于运算阶段,在这些语句运行前,实际上类的成员变量们就已经完成了初始化过程,构造函数内部对成员变量的改编只是一种赋值和运算行为.
    比如:

    001
    002
    003
    004
    005
    006
    007
    class A{
    public:
        A(int val):data(val){ cout<<data<<endl; }
        void print(){cout<<data<<endl;}
    private:
        const int data;
    };

    我们知道const类型只能在初始化时给定值,而不能之后赋值,所以,必须在初始化列表中给data初始化,而不能在函数体中去赋值.其他非const的成员即使初始化列表没有指定,进入函数体时,也已经有了相应的初始化值,int型可能是某个随机值.

    成员初始化的顺序与类的声明顺序一致.

    二. 构造函数

    关于构造函数还有更多复杂的专题,将另外重新写博客阐述.
    构造函数是可以重载的,编译器通过实参决定到底调用哪个构造函数

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    #include <iostream>
    #include <string>
    using namespace std;
    class A{
    public:
        A(int n,int m):data(10){ cout<<data<<endl; }
        A(float n, float m):data(12){ cout<<data<<endl; }
    private:
        int data;
    };
     
    int main()
    {
        A obj1(1,2.0);//10
        A obj2(1,2);//10
        A obj3(1.0f,2.0f);//12
        A obj4(1.0,2.0);//Error,不明确
        return 0;
    }

    另外隐式的类类型转换通常也是通过构造函数完成的。
    看如下的代码:

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    024
    025
    026
    027
    #include <iostream>
    #include <string>
    using namespace std;
     
    class A{
    public:
        A(int n):data(n,'a'){ cout<<data<<endl; }
        A(string str):data(str){ cout<<data<<endl; }
    private:
        string data;
    };
     
    //函数形参为A类型
    //空函数
    void f(A obj)
    {
    }
     
    int main()
    {
        //调用对应构造函数生成临时对象
        f(5);
        string myString("hello,world!");
        //调用对应的构造函数
        f(myString);
        return 0;
    }

    函数f的形参应该为A类型,但如果我们传入int或者string类型,编译器会调用相应的构造函数进行隐式的类型转换,生成一个临时的A的对象.
    如果要禁止这种隐式转换,可以使用关键字explicit(这个关键字只能用于类的内部构造函数声明,外部定义或者其他非构造函数不能使用).

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    024
    025
    026
    027
    028
    029
    030
    #include <iostream>
    #include <string>
    using namespace std;
     
    class A{
    public:
        explicit A(int n):data(n,'a'){ cout<<data<<endl; }
        explicit A(string str):data(str){ cout<<data<<endl; }
    private:
        string data;
    };
     
    //函数形参为A类型
    //空函数
    void f(A obj)
    {
    }
     
    int main()
    {
        //不能再使用直接传入5
        // error C2664: “f”: 不能将参数 1 从“int”转换为“A”
        //f(5);
        f(A(5));
        string myString("hello,world!");
        // error C2664: “f”: 不能将参数 1 从“std::string”转换为“A”
        //f(myString);
        f(A(myString));
        return 0;
    }

    三. this指针

    MSDN中关于this指针的描述是:

    The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions do not have a this pointer.

    static的成员变量或者函数是没有this指针的,(实际上static成员是属于类的,而不是属于对象,是同一类的对象间共享的,根本不可能有this指针).另外this指针实际上并不是对象本身的一部分,sizeof一个对象的计算值也并没有把它计算在内.

    下面的代码:

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    #include<iostream>
    using namespace std;
     
    class Simple
    {
    private:
        int m_nID;
    public:
        Simple(int nID)
        {
            SetID(nID);
        }
        void SetID(int nID) { m_nID = nID; }
        int  GetID() { return m_nID; }
    };
     
    int main()
    {
        Simple myob(5);
        myob.SetID(3);
        cout<<myob.GetID()<<endl;
        return 0;
    }

    其中myob.SetID(3)实际上被编译器解释为SetID(&myob,3),把对象的地址作为隐含的参数传给函数。
    另外this指针也可以用于防止自我调用.

    四. const关键字有关

    001
    double avg_price()const;
    将关键字const加入形参表之后,表示这个成员函数不能改变所操作的对象的数据成员,const必须同时出现在声明和定义中。
    关于为什么,更进一步的讨论如下:
    (1).在普通的非const成员函数中,this的类型是一个指向类类型的const指针,可以改变this所指向的值,但是不能改变this所保存的地址.
    (2).而在const成员函数中,this的类型是一个指向const对象的const指针,指向的值和保存的地址都不能改变.
    所以如果试图在const成员函数中返回this指针,必须说明返回的类型为const myClass&
    声明为mutable的成员是可变成员,即使在const对象或者const成员函数中也可以改变它的值.
  • 相关阅读:
    Kubernetes 集群日志管理
    登录功能通用测试用例设计
    Linux常用命令大全
    查看Android应用包名、Activity的几个方法
    CentOS 7 下Docker的安装
    Centos7.1下Docker的安装-yum方法
    appium+Java+testng自动化框架搭建-第一季
    Android在Win10环境搭建
    List<Map<String, Integer>> 同key的value全部累加合并
    Restrictions用法
  • 原文地址:https://www.cnblogs.com/shihao/p/2325560.html
Copyright © 2020-2023  润新知