首页 > 代码库 > C++primer笔记2:变量和基本类型、字符串,向量和数组、表达式、类

C++primer笔记2:变量和基本类型、字符串,向量和数组、表达式、类

第2章:变量和基本类型
char          8位
bool          未定义


short        短整型16
int          整型16
long         长整型32
long long    长整型64   C++11新定义的


float:  1个字  32位    6位有效位
double: 2个字  64位    10位有效位
long double:           10位有效位


带符号和不带符号的
unsigned   不带符号  仅仅表示大于0的
signed     带符号   大于,小于,0


基本字符集        :比特位
可寻址的最小内存块:字节    8比特
存储的基本单位    :字      32或64比特 就是4或者8个字节


8比特大小
0~255
-128~127

整型可以发分成两种:unsigned和signed
char可以发份成三种:char和unsigned char和signed char(实际表现就是两种,char会表现成其中的一种,而且char和signed char不同)



bool b=42  //实际上就是0和非0的分别,,而非0就是1,所以b为真(1)

注意:short太短,而int和long差不多一样的大小,
若是超过int表示的大小,应该用long long来进行表示,


单引号:字符     char
双引号:字符串   实际上用数组表示,字符串的结尾会加上空字符\0

a               //字符
"hello world"     //字符串
"b"               //字符串:实际上是b和空字符‘\0‘,不仅仅是单字符b


空字符:是在字符串的结尾来进行表示:\0   (单引号表示)
单引号和双引号:都是在英文下来进行表示


string:是一种库类型,表示一个可变长的字符序列,其表示是可变的长度大小
初始化:用列表{}来进行表示:int S[9]={0}   //初始化一个数组,用{}来表示
称为列表初始化
未初始化会引起运行时报错

变量声明和定义:
声明:只是规定了变量的类型和名字,extern关键字,表示声明
定义:不仅规定了变量的类型和名字,还申请了存储空间,也可能为变量赋一个初始值


extern int i;         //声明
int i;               //定义
extern int i=1//定义

为了支持分离式编译,C++语言将声明和定义区分开来,达到支持分离
变量能且只能定义1次,可以被声明多次,不能重复定义
C++是一种静态类型,是在编译阶段检查类型,实现类型检查



标示符:
1:变量:小写
2:类名:大写
3:多个单词之间应该有明显的区分,student_class,check_number,



复合类型:引用和指针

引用类型:为对象起了另外一个名字。&d,d是其他对象的别名而已,不是一个对象
引用即别名,并非对象,相反的,他只是为一个已经存在的对象起了另外1个名字

int i=10;
int &d=i;   //d指向i;d是i的别名
int &d=10;  //错误,引用类型的初始值必须是一个对象,而不是具体的值


指针:
指针本身就是一个对象,允许赋值和拷贝
在生命周期里,可以指向不同的几个对象
无须在定义时赋值,

int *p1,*p2;  //p1,p2都是指向int型对象的指针,即指向的对象是int型

指针存放某个对象的地址,要想获取该地址,需要使用取地址符&

int c=32;
int *p=&c;    //p存放的是变量c的地址,或者说p是指向c的指针

指针指向的对象是什么类型,指针就是什么类型,二者要保持高度的一致
因为指针指向了一个对象,所以可以用操作符*来访问对象

int c=10;
int *p=&c;
cout<<*p;   //输出10,*p表示指针指向对象的具体值  


空指针:nullptr
int *p1=nullptr;  //C++11新引入的nullptr空指针
int *p2=0;        //空指针
int *p3=NLUU;     //空指针


void* 特殊类型的指针,可以存放任意对象的地址
int *p1,*p2;  //定义两个指向int的指针
int* p1,p2;   //p1指向int的指针,p2是int
注意:为了防止误解,将*与变量放在一起,int *p;


const限定符:常量
const int bufSize=512;
如果在多个文件之间共享const对象,必须在变量之前加入extern关键字

常量指针:必须初始化,一旦初始化,就不会改变
int c=120;
int *const p=&c;   //常量指针


顶层const:
int i=0int *const p1=&i;        //针对指针,顶层const不可变,指针本身就是常量
const int *p2=&i         //针对常量,底层const可变,  指针指向的对象是个常量


constexpr:常量表达式
指针不会改变,而且在编译过程中就会得到计算结果的表达式
const int max=20;         //max是常量表达式
const int limit=max+1;    //limit是常量表达式
之前的常量表达式必须满足:
(1):const关键字
(2):编译时得到结果

C++11新引入的constexpr变量类型,以便可以由编译器来验证变量的值是不是一个常量表达式
constexpr int max=20;          //max是常量表达式
constexpr int limit=max+1;     //limit是常量表达式
constexpr int sz=size();       //只有当size是一个constexpr时才是正确的表达式


typedef:类型别名
类型别名:typedef:是一个名字,是某种类型的同义词,使复杂的类型名字变得简单明了,易于理解和使用
typedef double wages;     //wages是double的同义词
typedef wages  base,*p;   //base是double的同义词,p是double*的同义词
注意区分:引用相当于为变量取别名,typedef相当于为类型取别名


auto类型说明符:   C++11新引入auto类型变量,用它就能让编译器去分析表达式所属的类型
auto item=vall1+vall2;   //由vall1和vall2的类型来推断item的类型

decltype类型指示符:C++的新引入的类型推断,但是不想要计算该表达式的具体变量值,只想要类型
decltype(f())  sum=x; //sum的类型就是f函数的类型


注意区别:
引用      int &p=r;   
指针      int *p=&r;
取地址    &r


自定义数据结构:类类型
struct和class
先要用struct,再用class定义类

类通常被定义在头文件里面,类所在的头文件和类的名字应该保持一致,
头文件通常包含哪些只保存的定义1次的类,const,constexpr变量
头文件:类,const,constexpr


确保头文件多次仍能安全工作的技术:预处理器,它是在编译之前执行的一段程序
#include:预处理功能

头文件保护符:   #define
              #ifdef
              #ifndef
              #endif

#ifndef SALES_DATA_H;    //一般预处理变量都大写,避免冲突和头文件被多次包含,保证头文件只被包含1次
#def SALES_DATA_H;       //头文件保护符,保护头文件
#include<string>
struct Sales_data{
    string bookno;
    double prices;
};                       //分号表示对象类型的定义结束标志符,千万不要忘记分号
#endif


总结:
类型是C++编程的基础
面向对象:封装,继承,多态
类和对象:都是自己定义的类型
类型规定了其对象的存储要求和所能执行的操作,包含变量和方法
C++11新特性:
long long
列表初始化:{}
nullptr
constexpr
auto
decltype

C++的内置数据类型:
字符   整型  浮点型  
可变长字符串 向量
空字符:\0
bool char 
字符和字符串字面值  单引号和双引号
字符串的字面值类型实际上就是由常量组成的数组  结束符:空字符:\0

声明和定义:C++的分离式编译,在文件间共享代码
声明: 一个文件如果想使用别处定义的名字,则必须包含对那个名字的声明,extern关键字
定义:负责创建与名字相关联的实体

 

C++第3章:字符串,向量和数组

string和vector是两种重要的标准库类型
string:支持可变长字符串    只能是字符串数据本类型
vector:支持可变长的集合   可以是其他类型的的数据类型,不一定是字符串类型

内置数组是一种更基础的类型,灵活性不足
string和vector是对他的某种抽象
迭代器是string和vector的配套类型
迭代器的配套使用


命名空间:
using namespace std;

std::cin
std::cout
不用命名空间的话,就用上面的操作符作用域表示,很是麻烦
库函数一般都属于命名空间std
作用域操作符:(::)编译器从左侧的作用域中查找右侧的名字;


注意区分:
1:(::) 作用域
2:(:)   继承

头文件应该不包含using声明
标准库类型:string
表示可变长的字符序列
首先应该包含string的头文件
#include<string>

初始化:
string s1;
string s2(s1);    
string s3="value";            //拷贝初始化 
string s3("value")           //直接初始化
string s4(n,c)            //n个c连接的字符串

string s5=string(10,b)    //拷贝初始化
string s3="chen";           //拷贝初始化   注意字符串是"",数组是[],初始化的时候要区分开来
string s6("chen")          //直接初始化

string的操作:
s.size()       大小
s.empty() 
s[5]           引用
s1==s2
s1!=s2
getline(cin,s) 输入


string word;
while(cin>>word)    //循环输入,反复读取,直到文件的末尾
 cout<<word<<endl;


cout的输出不包含任何空格符,遇到空格符就停止
getline来读取一整行,并输入,遇到换行符就结束
size()函数表示字符串的长度,数组的长度用length()函数来表示


注意:C++中的字符串字面值和标准库函数类型中的string不是一个概念
所以string不一定就是字符串,字符串也不一定就是string,注意区分

字符串遍历:
string str="chennan";
for(char i:str)
    cout<<i<<endl;

string s1("hello word!")    //赋值字符串
decltype(s.size())  cnt=0;  //decltype用来判断是不是s.size()函数返回值的类型


只处理一部分字符串:下标或者索引[]
s[0]表示s中第一个字符串
——————————————————————————————————————————————————————————————————————————————————————————
vector 标准库类型  表示对象的集合  其中所有的集合数据类型都相同  
称为“容器”,每个对象都有一个称为对应的索引
#include<vector>

vector<int>  sale;
vector<sale_item> sale_item;
vector<vector<string>>  file;

vector是模板而不是类型,其他内置对象和类类型都可以作为vector的对象,不包含引用
vector<vector<int>>  包含容器的容器

初始化:vector<T> v5={A,B,C...}
        vector<T> v5{A,B,C...} 
        vector<T> v2(n,val)     //n个val
        vector<T> v1(n)         //n个初始化的对象


区分:
  string:    string s5=string(10,b)    //拷贝初始化
            string s3="chen";           //拷贝初始化   注意字符串是"",数组是[],初始化的时候要区分开来
            string s6("chen")          //直接初始化
 
  vector:    vector<T> v5={A,B,C...}
            vector<T> v5{A,B,C...} 
  vector<string> sec;

C++11的新标准的列表初始化:
vector<string>  articles={"a","an","abc"}


初始化的方法:
1:拷贝初始化
2:类内初始值
3:列表初始化


vector<int> v3(10,1);   //v3有10个元素,每个值是1
vector<int> v4{10,1};   //v4有两个元素,分别是10,1

向vector里面添加元素:push_back函数:
负责把一个值变成vector对象的尾元素压到尾端
vector<int>  v2;
for(int i=0;i!=10;i++)
    v2.push_back(i);    //push_back函数


string word;
vector<string> text;
while(cin>>word)
{
    text.push_back(word);
}


函数:
v.size
v.push_back(t)
v[n]
v1={a,b,c}

vector<int>::size_type 


//以10分为1个分数段统计成绩的数量:0~9,10~19,...90~99,100

vector<int> score(10,0);     //定义10个分数段,每个初始值为0
int grade;   
while(cin>>grade){           //读取成绩
    if(grade<=100)           //成绩有效值
        ++score[grade/10]    //将对应分数段加1;
}

vector对象(以及string对象)的下标运算可用于访问已经存在的元素,不能用于添加元素;
————————————————————————————————————————————————————————————————————————————————————————————————
迭代器:iterator
所有标准库函数都可以使用迭代器
v.begin() 和 v.end()
v.begin() :返回指向第一个元素的迭代器
v.end()   :尾后迭代器

使用迭代器
if(auto it=s.begin();it!=s.end()&&isspace(*it);++it)
*it=toupper(*it)   //将当前的字符串改写长大写字母

迭代器类型:包含两种
只读:const_iterator
读写:iterator


vector<int>::iterator it;           //读写
string::iterator it2;               //读写

vector<int>::const_iterator it3;    //只能读,不能修改
string::const_iterator it4;         //只能读,不能修改

vector<int> v;
const vector<int> cv;
auto it1=v.begin();     //it1是vector<int>::iterator
auto it2=cv.begin();    //it2是vector<int>::const_iterator

————————————————————————————————————————————————————————————————————————————————————————————————————————
数组:
数组大小确定不变,不能随意增加元素,运行时性能较好,但相应的也损失了灵活性
如果不清楚元素的个数,就使用vector

初始化:同样可以使用列表初始化
int arr[10];
int a2[]={0,1,2};
int a4[5]={0,1,2};

注意:数组不允许拷贝和赋值

指针也是迭代器
int arr[]={0,1,2,3,4,5,6};
int *p=arr;  //p指向第1个元素
++p;         //p指向第2个元素

标准库函数:
begin和end:C++新标准引入了针对数组的两个函数,与容器中的同名函数类似,只不过将数组作为他们的参数
int arr[]={1,2,3,4,5}
int *beg=begin(arr);       //指向首指针
int *end=end(arr);         //指向尾元素的下一个指针
——————————————————————————————————————————————————————————————————————————————————————————————————————————
C风格的字符串:
C标准库String函数:可以用于操作C风格字符串,他们在cstring头文件里面,cstring是C语言文件string.h的C++版本
C风格的字符串习惯:此习惯的字符串存放在字符数组里面,并以空字符串结束(\0)
strlen(p)             //长度
strcat(p1,p2)         //连接
strcpy(p1,p2)         //拷贝
strcmp(p1,p2)         //比较


多维数组:里外都使用{}来表示
int arr[3][4]={
    {0,1,2,3},
    {4,5,6,7},
    {8,9,10,11}
};
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
小结:
string和vector是两种重要的标准库类型
string:对象是一个可变长字符串序列
vector:一组同类型对象的容器

数组和指向数组元素的指针在一个较低的层次上实现了与标准库函数的string和vector的类似功能
先考虑标准库函数,再考虑C++的内置底层替代品数组或者指针


C风格字符串:以\0结束的字符数组,C风格容易出错
begin()和end()表示迭代器
difference_type:带符号整型,表示两个迭代器的距离
getline:string头文件的定义的函数,以一个istream对象和string对象作为输入参数:
getline(cin,word)
容器:一种类型,其对象容纳了一组给定类型的对象
迭代器:访问容器中的元素对象

size:string和vector的成员,分别返回字符的数量或者元素的数量
string:标准库函数,字符序列

范围for语句:一种控制语句,在值的一个特定范围内迭代

string初始化:
string s1="chenvvalue"     //拷贝初始化
string s2("chenvalue")     //直接初始化
getline(cin,s1)
s.size()
s.empty()
s[n]

string::size_type类型是size函数的返回值类型
注意:字符字面值和字符串字面值和string是不同的类型
当把string对象和字符串字面值混用时,必须确保每个+两侧至少有一个string
因为某些历史原因,也为了和C语言兼容,所以C++的字符串字面值并不是标准库函数string的对象
切记:字符串字面值和string是不同的类型


处理string对象中的字符,在cctype头文件的定义了一组标准库函数来处理这部分,
cctype头文件的函数:
isspace
isalnum
islower
issuper
tolower
toupper

范围for语句:string  str("chennan");
             for(auto i:str)
                 cout<<i<<endl;

处理部分字符:string s("chennan");
              s[0]
第4章:表达式
sizeof运算符:返回一条表达式的所占的字节数


隐式转换:自动转换   下降  float->int
显式转换:强制转换   提升  int->float


第5章:语句
条件:if     switch
迭代:for    while      do-while
跳转:break  continue   goto
终止:return 
异常:throw  try-catch


标准异常:
exception
stdexcept:
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————

第6章:函数

作用域和生命周期
函数应该在头文件里面声明,在源文件里定义
支持分离式编译

无返回值的函数:void返回值可以为空

函数重载:overloaded
函数名字相同,但形参列表不同(形参类型或者形参数量必须满足其中一个,或者都满足)
main函数不能重载
函数的名字仅仅是让编译器知道它调用的是哪个函数,函数重载在一定程度上减轻了起名字,记名字的负担

注意:函数重载应该在函数的形参的数量或类型有所不同
      不允许两个函数仅仅函数的返回类型不同,其他的所有要素都一样

隐藏名字:某个作用域内的声明会隐藏掉外层作用域的声明的同名实体


内联函数:inline  
请求编译器在可能的情况下在调用点展开函数,从而可以避免函数调用的开销
在每个节点上内联地展开
内联函数关键字:inline 
用于优化规模较小,流程简单,频繁调用的函数
很多编译器不支持内联递归调用


constexpr函数
用于常量表达式的函数
函数的返回类型和形参类型都要是字面值类型
且函数其中必须有且只有1条return语句
constexpr函数不一定返回常量表达式

把内联函数和constexpr函数放在头文件里面

调试帮助:assert和NDEBUG
程序可以包含一些用于调试的代码,但是这些代码只是在开发程序的时候使用,当程序发布的时候,要屏蔽掉这些代码

assert:预处理宏或者预处理变量
assert(expr);作用于1条表达式
首先对expr求值,如果表达式为假,即为0,assert输出信息并终止程序的执行
                如果表达式为真,即非0,assert什么也不做
assert在预处理器里面,定义在cassert头文件里面,只与预处理器有关,与编译器无关


NDEBUG:预处理变量
如果定义了NDEBUG,则assert什么也不做,就不会做调试和检查
但是默认状态下没有定义NDEBUG,所以assert会做相应的检查
可以用一个#define语句来定义NDEBUG,从而可以关闭调试状态
因此定义NDEBUG能够避免检查各种条件使用的运行时开销

根据调用时使用的实参,编译器可以自动的选定被调用的函数,
从一组重载函数里面选取最佳函数的过程成为函数匹配


函数匹配:编译器在解析重构函数的调用过程中,会将实参与每个重载函数的形参一一比较


总结:
局部变量:形参和函数体内部定义的变量统称为局部变量,仅仅在函数的作用域内可见         
自动对象:只存在于块执行期间的对象成为自动对象,当块执行结束后,块中创建的对象就会变成未定义的,形参就是一种自动对象



顶层const:
const int ci=10;   //顶层常量
int * const p=&i;  //顶层指针

当用实参初始化形参的时候会忽略掉顶层的const,所以形参的顶层const会被忽略掉了
当形参有顶层const时,传给它的常量或者非常量对象都是可以的,即const被忽略掉了
数组引用形参:C++允许将变量定义为数组的引用:void fun(int (&arr)[10]){};   //注意(&arr)括号不能少

含有可变形参的函数:当我们无法提前预知应该向函数传递几个参数的时候
C++提出了两种主要方法:如果所有实参类型相同,可以传递1个 initializer_list的标准库类型
                       如果实参类型不相同,编写一种特殊函数:可变参数模板
                      C++还有1种特殊的形参类型:省略符,用于传递可变数量的形参,不过它只用于与C函数交互的接口程序

(1)initializer_list   (形参标准库,定义在同名的头文件里面)  
(2)可变参数模板       (函数)
(3)省略符             (形参)


initializer_list的标准库类型
initializer_list<string>  il;           //和vector<string>类似,只不过里面的元素只有常量
(beg=il.begin();beg!=il.end();++beg)    


省略符形参:便于C++访问某些C语言程序设置的
代码使用了varargs的标准库功能
void foo(parm_list,...);
void foo(...);


主函数main的返回值:
正常情况:如果返回类型不是void,必须要有return返回值
但是我们允许main函数没有return语句而可以直接返回,因为编译器默认隐式插入1条返回0的语句
返回0表示执行成功,返回其他执行失败
如果让返回与机器无关,cstdlib头文件定义了两个预处理变量:
return EXIT_FIALURE;   //定义在cstdlib头文件里面
return EXIT_SUCCESS;   //定义在cstdlib头文件里面

递归:如果一个函数调用了他自身,不管是直接的还是间接地,都称为递归函数
int factorial(int val)
{
    if(val>1)
        return factorial(val-1)*val;
    return 1;   //val为1时,递归终止,return语句0代表成功,非0都是失败
}
//main函数不能调用它自己
C++笔记第5章:类

面向对象:万物皆对象,我们可以设计自己的类型,就是类类型
面向对象:封装,继承,多态
类的基本思想:数据抽象和封装
数据抽象:依赖于接口和实现的分离编程技术
封装:隐藏了类的具体实现细节

包含成员变量和成员方法

构造函数:类通过1个或者几个特殊的成员函数来完成对象的初始化
只要类的对象被构建,就会执行构造函数,
名字和类名相同,没有返回类型,参数列表和函数体可以为空
可以包含很多构造函数,不能被声明为const


访问修饰符:
public:  在整个程序里都可以被使用,  包括构造函数,部分成员函数
private: 可以被类里面的成员函数访问,包含数据成员,实现部分的函数

class和struct的区别:默认访问权限不同
在第1个访问修饰符之前定义的成员:对于class和struct的访问修饰符是不同的
structpublic
classprivate


友元:friend
类可以允许其他类或者函数访问它的非公有成员,方法是:让其他类或者函数称为它的友元(friend)
关键字:friend
友元声明只能出现在类定义的内部,
友元不是类的成员,也不受它所在区域访问控制级别的约束
一般最好定义在开始的时候



委托构造函数:C++11扩展了构造函数的初始值的功能,使得委托构造函数可以使用所属的类的其他构造函数来执行自己的初始化
就是它把自己的一些指责委托给了其他构造函数

explicit:抑制构造函数的隐式转换
explicit构造函数只能用于直接初始化


聚合类:使得用户可以直接访问成员,并且具有初始化的功能
所有成员都是public
没有定义任何构造函数
没有类里初始值
没有基类,没有virtual函数,


字面值常量类:尽管构造函数不能是const的,但是字面值常量类的构造函数可以是constexpr的;
一个字面值常量类至少提供一个constexpr构造函数


类的静态成员:有时候类需要它的一些成员与类本身有关,而不是与各个对象保持关联
声明静态成员:static
类的静态成员存在于任何对象之外,对象中不包含任何与静态成员有关的数据
类的静态成员不能声明成const的,而且不能在static内部使用this指针
即static不能与this和const一起使用


使用作用域运算符来直接访问静态成员
可以使用类的对象,引用或者指针来访问静态成员
成员函数不用通过作用域运算符就能直接使用静态成员


static关键字只能出现在类内部的声明语句
既可以在类的内部定义也可以在类的外部定义静态成员函数
不能在类的内部初始化静态成员,相反,要在类的外部初始化每个静态成员,
一个静态成员只能被定义1次

如果静态成员是字面值常量表达式constexpr,就可以在类的内部完成类的静态成员初始化
我们可以为静态成员提供const整数类型的类内初始值


静态成员独立于任何对象
静态成员可以是不完全类型(就是类类型)
而非静态类型受到限制,只能声明为它所属的指针或者引用
静态成员忽然普通成员的区别:我们可以使用静态成员作为默认实参
非静态成员不能作为默认实参,因为它的值本身属于对象的一部分,这样无法为其提供一个真正的对象以便从中获取成员的值
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————
类的两项基本功能:
一是数据抽象:定义数据成员和函数成员的能力
二是封装:保护类的成员不被随意访问的能力,可以将类的细节设为private就能完成类的封装
          类可以将其他类或者函数设为友元,这样就可以访问类的非公有成员

类可以定义一种特殊的成员函数:构造函数
作用:控制初始化对象的方式
构造函数可以重载,应该使用构造函数来初始化所有数据成员

静态成员:可以是函数或者数据
静态成员存在于所有对象之外



类的声明:class或者struct,如果类已经声明但尚且未定义:则他是一个不完全类型
class关键字:定义类的关键字,默认情况下成员是private
struct关键字:定义类的关键字,默认情况下成员都是public
聚合类:只含有公共成员,没有类内初始值,没有构造函数
聚合类的成员可以用初始值列表来进行初始化,(用花括号括起来)

数据抽象:着重关注类型接口的一种编程技术
          让程序员可以忽略类型具体的实现细节
          数据抽象是面向对象编程和泛型编程的基础


友元:可以是类,也可以是函数
封装:分离类的实现与接口,从而隐藏了类的实现细节,通过把实现部分设为private完成封装


类的基本思想:数据抽象和封装

               数据抽象:依赖于接口和实现分离的编程技术
               类的接口:包含用户所有能执行的操作
               类的实现:类的数据成员,负责接口实现的函数体和定义类的各种私有函数

               封装:实现了类的接口和实现的分离
               封装后的类隐藏了他的实现细节,
               类的用户只能使用接口而无法实现访问部分


尽管所有成员都必须在类内部声明,但是成员函数可以定义在类内,也可以定义在类外
定义在类内的成员函数:隐式的inline函数



常量成员函数
例如:string isbin() const {return bookNo;}
引入const成员函数:修改隐式this指针的类型
默认this的类型:指向类类型非常量版本的常量指针          Sales_data *const
当我们把this设置为指向常量的指针有助于提高函数的灵活性  const Sales_data *const
C++允许把const关键字放在成员函数的参数列表后面,表示this是指向一个常量的指针
向这样使用const的成员函数称为常量成员函数
常量对象,以及常量对象的引用或者指针只能调用常量成员函数



可以在类的外部定义成员函数,此时成员函数的定义必须与它的声明一致
类外部定义的成员的名字必须包含它所属的类名
double Sales_data::avg_price() const{
    if(units_sold)
        return revenue/units_sold;
    else
        return 0;
}

定义类相关的非成员函数:
类的作者通常需要定义一些辅助函数:add,read,print,
尽管这些函数定义的操作从概念上属于类接口的一部分,实际上并不属于类本身
这些非成员函数的声明应该与类在同一个文件夹内
而且通常需要把函数的声明和函数的定义分离开来


构造函数:完成初始化
          无返回类型
          名字与函数同名
          有参数列表:但可为空
          有函数体:  但可为空
          不能为const

默认构造函数
合成的默认构造函数:编译器默认创建的构造函数

=default  C++11里面的默认需要使用构造函数的时候,就会要求编译器生成构造函数
=default可以在类的内部,也可以在类的外部
如果在内部:内联的默认构造函数
如果在外部:此时默认构造函数不是内联的

构造函数初始化列表:
Sales_data(const std::string &s):bookNo(s) {}
Sales_data(const std::string &s,unsigned n,douple p):bookNo(s),units_sold(n),reverne(p*n)  {}


拷贝,赋值,析构:
动态分配和管理对象外的资源的时候,使用string和vector的类能够避免分配和释放内存带来的麻烦
_____________________________________________

 

C++primer笔记2:变量和基本类型、字符串,向量和数组、表达式、类