单词 ——> 表达式 ——> 语句 ——> 函数 ——> 类
数据类型决定了程序中的数据和操作的意义。
内置类型体现了硬件本身的能力特性。
unsigned char c = -1 // c的值为255
一条声明语句由一个基本数据类型(base type)和紧随其后的一个声明符(declarator)列表组成。
对象(object):通常指一块能存储数据并具有某种类型的内存空间。
引用为对象起了另外一个名字,引用类型引用另外一种类型。通常将声明符写成 &variable
的形式来定义引用类型。
引用的类型必须与其所引用对象的类型一致。但有两个例外:
指针是指向另外一种类型的复合类型。实现了对其他对象的间接访问。
利用指针访问对象
空指针
void*
指针
指向指针的指针 int **ppi = &pi
指向指针的引用 int *&r = p
因为引用本身不是一个对象,所以不能定义指向引用的指针。
指针的类型必须与其所指对象的类型一致。但有两个例外:
关键字const
对变量的类型加以限定。
常量引用
typedef
作为声明语句中的基本数据类型的一部分using SI = Sales_item
1. struct Sales_data {
}trans,*salesptr;
2. struct Sales_data {
};
Sales_data trans,*saleptr;
确保头文件多次包含但仍能安全工作的常用技术是预处理器。
#include
#ifndef... #define... #endif
push_back
begin
,end
condition ? expr1 : expr2
sizeof (type)
sizeof expr
隐式类型转换的时机:
cast_name(expression)
;
if-else if-else
switch...case
do...while
while
for
break
continue
throw
try...catch
return;
return {...}
auto func(int i) -> int(*)[10]
如果统一作用域内的几个函数名字相同但形参列表不同,则称之为重载函数。
const string &shorterString(const string &s1,const string &s2) {
reutrn s1.size() <= s2.size() ? s1 : s2;
}
string &shorterString(string &s1,string &s2) {
auto &res = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(res);
}
函数指针指向的是函数而不是对象。函数指针指向某种特定类型,函数的类型由它的返回类型和形参类型决定,与函数名无关。
bool lengthCompare(const string &,const string &);
bool (*pf)(const string &,cosnt string &);
某些函数有这样一种形参,在函数的很多次调用中都被赋予相同的值,此时,可以将这个反复出现的值成为函数的默认实参。
将函数声明为inline
,通常就是将它在每个调用点上“内联”地展开,可以避免函数调用的开销。
能用于常量表达式的函数。
assert
宏定义在cassert
头文件中,由预处理器而不是预编译器管理。】NODEBUG
类的基本思想是数据抽象与封装。要想实现这两点,需要首先定义一个抽象数据类型。
在C++中,使用访问说明符来加强类的封装性。
public
:定义在public说明符后的成员在整个程序内可被访问,public成员定义类的接口。private
:可以被类的成员函数访问,封装(隐藏)了类的实现细节。class与struct的对比:默认访问权限不同
class
:定义在第一个访问说明符前的成员是private的struct
:定义在第一个访问说明符前的成员是public的除了定义类的对象如何初始化,类还需要控制拷贝、赋值和销毁对象时发生的行为。如果不主动定义这些操作,编译器将默认合成这些操作。
但是对于某些类来说,这些合成的版本可能无法正常工作。如分配和管理动态内存的类。不过,很多需要动态内存的类能使用vector对象或者string对象管理必要的存储空间,使用vector和string的类能避免分配和释放内存带来的复杂性。
一个类就是一个作用域。在类的作用域外,普通的数据和函数成员只能由对象、引用或指针使用成员访问运算符来访问。对与类类型成员则使用作用域运算符访问。
类可以自定义某种类型在类中的别名。如using pos = std::string::size_type
或typedef std::string::size_type pos
。
如果希望修改类的某个数据成员,即使是在一个const成员函数内。可以通过在变量声明中加入mutable
关键字实现。
一个可变数据成员不会是const,即使它是const对象的成员。
可以把类名作为类型的名字使用,从而直接指向类类型。如Sales_data item
或class Sales_data item
。
class Screen
,对于类型Screen
来说,在它声明之后定义之前是一个不完全类型。通过引入友元函数或者友元类来控制外部类对私有成员的访问权限。
每个类定义了它的对象被初始化的方式,这些控制初始化过程的函数被称为构造函数。构造函数的任务是初始化类对象的数据成员,只要类的对象被创建,就会执行构造函数。
当没有声明构造函数时,编译器会合成一个默认的构造函数来执行初始化过程,可能是默认初始化或者用类内的初始值来初始化数据成员。如Sales_data() = default;
某些类不能依赖于默认构造函数:
默认构造函数的作用:当对象被默认初始化或值初始化时自动执行默认构造函数。
默认初始化发生时机:
值初始化发生时机:
T<>
形式的表达式显式地请求值初始化时class Sales_data {
public:
Sales_data() = default;
Sales_data(std::string s = ""): bookNo(s) {
}
};
两种方式的唯一区别是:
转换构造函数:如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。
explicit
关键字,只能用于直接初始化class Sales_data {
public:
Sales_data(const std::string &s): bookNo(s) {
}
Sales_data(std::istream&);
explict Sales_data(const std::string &s): bookNo(s) {
}
explict Sales_data(std::istream&);
Sales_data &combine(const Sales_data&);
};
string null_book = "9-999-999-9999";
Sales_data item;
1. item.combine(Sales_data(null_book));
2. item.combine(static_cast<Sales_data>(cin));