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; // 错误,数据成员必须是完全类型
}
C++Primer笔记-----day06的更多相关文章
- C++ Primer笔记
C++ Primer笔记 ch2 变量和基本类型 声明 extern int i; extern int i = 3.14;//定义 左值引用(绑定零一变量初始值,别名) 不能定义引用的引用:引用必须 ...
- C++ Primer 笔记(1)基础中的战斗机 输入输出 对输入不定数据处理
今天打算再重新好好的看一遍C++ Primer这本很经典的书籍,笔记开始: 1.每个C++程序都包含一个或者多个函数,其中必须有一个main,操作系统通过调用main入手运行程序: 2.函数包括:返回 ...
- C++ Primer 笔记 第一章
C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...
- C++primer笔记之顺序容器
最近又重新拾起C++primer,发现每一次看都会有不同的体验,但每一次看后因为不常用,忘记得很快,所以记笔记是很关键的一环,咋一看是浪费时间,实际上是节省了很多时间.下面就把这一节的内容做一个简单的 ...
- c++ primer 笔记 (一)
昨天开始看的<C++ Primer>,确实不错.希望这周抓紧看完,每天做下笔记,以便以后复习. main函数返回一个值给操作系统 操作系统通过main函数返回的值来确定程序是否成功执行 ...
- C++ Primer笔记(1)——连续读取数据、类型对应的尺寸、类型转换、字符串分行写法
这次要看看C++ Primer,这本基本上就是必读书籍了.下面的内容就是一些之前没有学过的知识的笔记. 读取数量不定的输入数据 虽然很简单,但是还是记一下: #include <iostream ...
- C++Primer笔记(3)
标准库类型string表示可变长的字符序列,使用前先包含string头文件.(哈哈,终于可以逃脱C语言中的str函数系列了.)因为是标准库的一部分,所以string被定义在命名空间std中.所以你懂该 ...
- C++ Primer 笔记 第三章
C++ Primer 第三章 标准库类型 3.1using声明 例: using namespace atd; using std::cin; 3.2string类型 初始化方式 string s1 ...
- C++ Primer 笔记 第二章
C++ Primer 第二章 变量和基本类型 2.1基本内置类型 有算数类型和void类型:算数类型储存空间大小依及其而定. 算数类型表: 类型 含义 最小储存空间 bool 布尔型 - char 字 ...
随机推荐
- Android Hook框架Xposed详解
1 Introduction 1.1 概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...
- Java中有两种实现多线程的方式以及两种方式之间的区别
看到一个面试题.问两种实现多线程的方法.没事去网上找了找答案. 网上流传很广的是一个网上售票系统讲解.转发过来.已经不知道原文到底是出自哪里了. Java中有两种实现多线程的方式.一是直接继承Thre ...
- C#/.NET 读取或修改文件的创建时间和修改时间
手工在博客中添加 Front Matter 文件头可是个相当费事儿的做法,这种事情就应该自动完成. .NET 中提供了非常方便的修改文件创建时间的方法,使用这种方法,能够帮助自动完成一部分文件头的编写 ...
- C++ set容器
STL中的set容器的一点总结:(元素唯一,且排序) 1.关于set (头文件:<set>) C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, strin ...
- functool.wraps and functools.partial
functools.partial 通过包装手法,允许我们 "重新定义" 函数签名. 通常是将函数的部分参数给固定下来, 从而形成一个输入参数更少的新函数. functool.w ...
- @contextmanager
with的作用,类似try...finally...,提供一种上下文机制. 要应用with语句的类,其内部必须提供两个内置函数__enter__以及__exit__ , 前者在主体代码执行前执行, ...
- Oracle分组函数实例
分组函数也叫聚合函数.如果在查询只想要查分组函数,那么跟平时的查询语句并无不同: SQL ,,,,) ; SUM(T.PRIZENUM) AVG(T.PRIZENUM) --------------- ...
- jdk1.8新特性之接口default方法
众所周知,default是java的关键字之一,使用场景是配合switch关键字用于条件分支的默认项.但自从java的jdk1.8横空出世以后,它就被赋予了另一项很酷的能力——在接口中定义非抽象方法. ...
- 面试常考知识点——Java(JVM,JDK,JRE)
1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 答:(1)Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. ...
- HTTP 报文首部
1.HTTP 报文首部 HTTP 协议的请求和响应报文中必定包含 HTTP 首部.首部内容为客户端和服务器分别处理请求和响应提供所需要的信息. 1)HTTP请求报文:在请求中,HTTP报文由方法.UR ...