欢迎光临
我们一直在努力

类和对象(下)

文章目录

  • 1、构造函数补充
    • 初始化列表
  • 2、类型转换
  • 3、static成员
  • 4、匿名对象
  • 5、友元
  • 6、内部类
  • 7、对象拷贝时的编译器优化

1、构造函数补充

初始化列表

之前对类的成员初始化是在函数体内实现,但严格意义上来说,这不是初始化,而是赋初值。要想对成员进行真正的初始化,就需要使用初始化列表。 格式:固定格式,初始化列表必须写在构造函数的参数列表之后、函数体的左大括号 { 之前,并且以冒号 : 开头,结尾无 ; 。

构造函数 :成员1(表达式1或值1), 成员2(表达式2或值n), … 成员n(表达式n或值n) { //… }

注意事项:

  • 每个成员变量在初始化列表中只能出现⼀次,初始化只有一次。
  • 成员初始化的顺序与初始化列表处成员出现的先后无关,与成员声明处出现的先后有关。
  • #include<iostream>
    using namespace std;

    class A {
    public:
    //构造函数
    A(int b)
    :_b(b)
    ,_a(_b)//先初始化
    {}

    //打印成员
    void Print()
    {
    cout << "_a->" << _a << " _b->" << _b << endl;
    }
    private:
    int _a;//先初始化
    int _b;
    };
    int main()
    {
    A a(1);
    a.Print();
    return 0;
    }

    在这里插入图片描述

  • C++11支持在成员声明处给缺省值,用于辅助初始化列表,若该成员没有在初始化列表初始化,那么它用缺省值初始化。
  • class A {
    public:
    A(int a)
    {

    }

    void Print()
    {
    cout << _a << endl;
    }

    private:
    int _a = 3;
    };

    int main()
    {
    A a(1);
    a.Print();

    return 0;
    }

    在这里插入图片描述

  • 有三类成员必须放在初始化列表位置进行初始化,否则会编译报错。这是面试高频考点。
  • (1) 引用成员变量

    class A{
    public:
    A(int& a)
    :_a(a)
    {}
    private:
    int& _a;
    };

    (2)const成员变量

    class A{
    public:
    A(int b)
    :_b(b)
    {}
    private:
    const int _b;
    };

    (3)没有默认构造的类类型变量

    class A {
    public:
    A(int a)//显示定义构造函数
    {
    _a = a;
    }
    private:
    int _a = 1;
    };

    class B {
    public:
    B()
    :_c(1)
    {}
    private:
    A _c;
    };

    5.一个类,无论成员在不在初始化列表初始化,无论有没有初始化,调用该类时编译器都会在初始化列表走改成员初始化。如果该成员是内置有缺省值用缺省值,没有则给随机值;如果该成员是自定义类型,有默认构造走默认构造,没有就报错。

    2、类型转换

  • C++支持内置类型的隐式类型转换为类类型的对象,但需要相关类型的构造函数。
  • class A {
    public:
    A(int a)
    :_a(a)
    {
    }
    private:
    int _a;
    };

    class B {
    public:
    B(int a,int b)
    { }
    private:
    int _a;
    int _b;
    };

    int main()
    {
    //单参数转换
    A a = 1;

    //多参数转换
    B b = { 1,2 };
    return 0;
    }

  • 类类型对象之间支持隐式类型转换
  • class A {
    public:
    A(int a)
    :_a(a)
    { }
    void Print()
    {
    cout << _a << endl;
    }
    private:
    int _a;
    };

    int main()
    {
    A a = 1;

    A b = a;//a隐式转换为int类型

    b.Print();
    return 0;
    }

  • 构造函数前加explict后,不在支持隐式类型转换。
  • class A {
    public:
    explicit A(int a)
    :_a(a)
    {
    }
    private:
    int _a;
    };

    int main()
    {
    A a = 1;
    return 0;
    }

    在这里插入图片描述

    3、static成员

  • static修饰的变量称为静态成员变量,静态成员变量的声明不能在类中,只能在全局。声明时要指定类域。静态成员不能给缺省值,也不走初始化列表。
  • 静态成员变量存在静态区,属于改类型所有对象公有。
  • class A{
    public:

    void Print()
    {
    cout << _b << endl;
    }

    private:
    static int _b;
    };

    //静态成员初始化
    int A::_b = 1;

    int main()
    {
    A a;
    a.Print();
    A b;
    b.Print();

    return 0;
    }

    在这里插入图片描述

  • static修饰的成员函数叫做静态成员函数。静态成员函数没有this指针,只能访问静态成员, 受访问限定符限制。
  • 突破类域就可以访问静态成员。可以通过 类名::静态成员 或者 对象.静态成员 来访问。
  • class A {
    public:

    void Print()
    {
    cout << _b << endl;
    }

    //private:
    static int _b;
    };

    int A::_b = 1;

    int main()
    {
    A a;
    //直接访问_b要设为公有
    cout << A::_b << endl;
    cout << a._b << endl;

    return 0;
    }

    在这里插入图片描述

    4、匿名对象

    创建一个没有名字的对象称为匿名对象,它的生命周期只在它定义的那一行,那一行结束自动调用析构。

    class A{
    public:

    A(int a)
    :_a(a)
    {
    cout << "A(int a)" << endl;
    }

    void Print()
    {
    cout << _a << endl;
    }

    private:
    int _a;
    };

    class Stack {
    public:
    //构造函数
    Stack(int n = 4)
    {
    cout << "Stack(int n = 4)" << endl;
    int* tmp = (int*)malloc(n * sizeof(int));
    if (tmp == nullptr)
    {
    perror("malloc fail");
    return;
    }
    array = tmp;
    size = n;
    capacity = 0;
    }

    //析构函数
    ~Stack()
    {
    cout << "~Stack()" << endl;
    if (array != nullptr)
    {
    free(array);
    array = nullptr;
    capacity = size = 0;
    }
    }

    private:
    int* array;
    int capacity;
    int size;
    };

    int main()
    {
    Stack();
    A(1).Print();

    return 0;
    }

    在这里插入图片描述

    5、友元

  • 友元提供了⼀种突破类访问限定符封装的方式,在类名和函数申明前加 friend 称为友元类和友元函数,⼀个函数可以是多个类的友元函数。
  • 外部友元函数可以访问类的私有,不属于类的成员函数。
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  • class A {
    public:
    //定义在公有
    friend void Print(const A& a, const B& b);
    A(int a)
    :_a(a)
    {}
    private:
    int _a = 0;
    };

    class B {
    public:
    B(int b)
    :_b(b)
    {
    }
    private:
    //定义在私有
    friend void Print(const A& a,const B& b);
    int _b = 0;
    };

    void Print(const A& a, const B& b)
    {
    cout << a._a << endl;
    cout << b._b << endl;
    }

    int main()
    {
    A a = 1;
    B b = 2;
    Get(a, b);
    return 0;
    }

    在这里插入图片描述

  • A是B的友元,B是C的友元,那么B不是A的友元,友元是单向的;A不是C的友元,友元不能传递。
  • 友元会增加耦合度,破坏了封装,所以友元不宜多用。
  • 6、内部类

  • 定义在类中的类称为内部类,内部类默认是外部类的友元,内部类可以访问外部类的成员。
  • 如果A类频繁访问B类的成员,那可以将A类作为B的内部类。如果A为私有,那么A就成B的专属。
  • class B {
    public:
    //构造函数
    B(int a,int b)
    :_a(a),_b(b)
    { }

    //内部类
    class A {
    public:
    //打印_b
    void Print_b(const B& b)
    {
    cout << b._b << endl;
    }

    private:
    int _a;
    };

    private:
    int _a;
    int _b;
    };

    int main()
    {
    B b = { 10,20 };

    B::A a;

    a.Print_b(b);

    return 0;
    }

    7、对象拷贝时的编译器优化

  • 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传返回值的过程中可以省略的拷贝。
  • C++标准并没有严格规定怎么优化,各个编译器会根据情况自行处理。
  • class A {
    public:
    A(int a = 1)
    :_a(a)
    {
    cout << "A(int a)" << endl;
    }

    A(const A& a)
    {
    cout << "A(const A& a)" << endl;
    this->_a = a._a;
    }

    A& operator=(const A& a )
    {
    cout << "A& operator=(const A& a )" << endl;
    this->_a = a._a;
    return *this;
    }

    ~A()
    {
    cout << "~A()" << endl;
    }

    private:
    int _a = 0;
    };

    void f1(A aa)
    {
    }

    A f2()
    {
    A aa;
    return aa;
    }

    int main()
    {
    // 传值传参
    // 构造+拷贝构造
    A aa1;
    f1(aa1);
    cout << endl;

    // 隐式类型,连续构造+拷贝构造->优化为直接构造
    f1(1);
    cout << endl;

    // ⼀个表达式中,连续构造+拷贝构造->优化为⼀个构造
    f1(A(2));
    cout << endl;

    //…
    return 0;
    }

    赞(0)
    未经允许不得转载:171主机测评 » 类和对象(下)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址