zoukankan      html  css  js  c++  java
  • C++Primer笔记-----day06

    ================================================================
    day06
    ================================================================
    1.初始化和赋值是有区别的,前者效率更高。有时候必须使用初始化。
    如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为
    这些成员提供初始值。
    注意:数据成员会按其出现在类定义中的顺序得到初始化,而不是按其在初始值列表中的顺序。
    2.如果一个构造函数为【所有参数都提供了默认实参】,则它实际上也定义了默认构造函数。(不是合成的默认构造函数)
    举例:
    class A {
    public:
    A(int a = 5, double b = 3.0)
    { v1 = a;
    v2 = b;
    cout << v1 << " "<< b <<endl;
    }

    private:
    int v1 = 0;
    double v2 = 0.0;

    };

    A m; // 虽然没有显式定义默认构造函数,但因为构造函数所有参数都提供了默认实参,所以正确。会输出: 5 3.0
    A n(10,3.14); // 调用了构造函数A(int a = 5,double b = 3.14) 会输出:10 3.14

    3.Sales_data obj(); // 这种用法的语法是正确的,但与我们的初衷不符:定义了一个函数【而非对象!】
    如果想定义一个使用默认构造函数进行初始化对象,正确方法是去掉对象名之后的空的括号对。
    Sales_data obj;
    =================================================================================
    4.隐式类类型转换。
    如果构造函数只接收一个实参,那么它实际上定义了转换为此类类型的隐式转换机制。
    eg:
    class Sales_data{
    public:
    Sales_data() = default;
    Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
    Sales_data(const string &s):bookNo(s){}
    Sales_data(std::istream &);

    Sales_data &combine(const Sales_data&);
    private:
    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
    };
    这个类只接受一个实参的构造函数为接受string的构造函数和接受istream的构造函数。它们分别定义了从这两种类型
    向Sales_data隐式转换的规则。也就是说,需要使用Sales_data的地方,我们可以用string或者istream代替。
    string null_book = "9-999-9999-9";
    item.combine(null_book); // 因为隐式转换的存在,我们用一个string实参调用了Sales_data的combine成员。
    编译器用给定的string自动创建了一个Sales_data对象。然后这个临时对象被传递给combine。
    注意!这个临时量是const的,而combine接受的实参也是const引用,所以可以传递。如果换成Sales_data &combine(Sales_data&)则会编译错误!
    注意,编译器只会执行一步隐式类型转换。
    eg: item.combine("9-999-9999-9"); //错误,不能把“9-999-9999-9”转换为string,再把string转换为Sales_data。编译器只会执行一步类型转换。
    可以这样做:item.combine(string("9-999-9999-9"));//显式转换为string,再隐式转换成Sales_data
    或: item.combine(Sales_data("9-999-9999-9")); // 隐式转换为string,再显式转换为Sales_data

    如果我们不想这样的构造函数进行隐式转换,可以在声明前加explicit阻止。
    explicit只对一个实参的构造函数有效,而且【只能在类内声明构造函数时使用,类外定义时不能重复!】

    ==============================================================================
    5.聚合类。
    如果一个类:
    所有成员都是public、
    没有定义任何构造函数、
    没有类内初始值、
    没有基类和virtual函数, 那么它就是一个聚合类。 聚合类有特殊的初始化语法形式:
    struct Data{
    int ival;
    string s;
    }
    Data val1 = {0,"Anna"}; 初始值的顺序必须与声明顺序一致!如果初始值列表中的元素个数少于类的成员数量,则靠后的成员被值初始化。

    6.有时候,我们需要类的一些成员只与类本身有关,而不是与类的各个对象有关联。
    比如,一个银行类可能需要一个数据成员表示利率。从实现的效率来说,没必要每个对象都存储利率信息,
    更重要的是,一旦利率浮动,我们希望所有对象都使用新值。
    这时,我们可以把它声明为static。 可以用className::来访问静态成员。虽然静态成员不属于某个对象,但
    仍然可以通过对象和【.操作符】来访问它。
    我们既可以在类的内部,也可以在类的外部定义静态函数,但static关键字只能出现在类内部的声明语句。在类外部定义时,不可以重复static关键字!(与explicit相似)
    类内的static数据成员,只能在类外定义,【除非它被声明为const(或者constexpr)】。它的定义一般和类的其他非内联函数的定义放到同一个文件。
    class A{
    private:
    int a = 5; // 正确,表示类内初始值
    const int b = 10; // 正确
    static int c = 15; // 错误
    static constexpr int d = 20; // 正确
    }
    注意:类的静态方法只能访问类的静态成员!!可以是private和protected。

    静态数据成员可以是不完全类型,而非静态数据成员则受到限制,只能声明成它所属类的指针或引用。
    class Bar{
    public:

    private:
    static Bar mem1; // 正确,静态成员可以是不完全类型
    Bar *mem2; // 正确,指针类型可以是不完全类型
    Bar mem3; // 错误,数据成员必须是完全类型
    }

  • 相关阅读:
    Flash 全局安全性设置面板
    响应式布局的一个例子mark
    移动平台WEB前端开发技巧汇总
    自定义事件机制——观察者模式
    学习之响应式Web设计:Media Queries和Viewports
    常用栅格布局方案
    观察者模式的一个例子
    二进制文件转换为文本工具
    C#面向对象名词比较(二)
    MSN消息提示类
  • 原文地址:https://www.cnblogs.com/ll-10/p/9606804.html
Copyright © 2011-2022 走看看