本章主要讲了标准库类型,其中主要从以下几个方面进行了说明。
第一:命名空间的using声明:
第二:标准库string类型:定义和初始化(三种)、读写、getline/string重点
第三:标准库vector类型:定义和初始化、对象操作
第四:迭代器简介(不懂)
第五:标准库bitset类型(不懂)
小结:
①变量和基本类型等都是低级数据类型,标准库类型更为高级更为抽象。其中最为重要的为string和vector标准库类型。
②使用using声明可以在不需要加前缀namespace_name::情况下,一个using只能作用于一个命名空间成员。
③using std::cin; using std::cout; using std::endl; 后面程序中可以不写std::.
④getline函数用于读取整行,eg:while (getline(cin,line)) ^^^^^^^return 0;
⑤vector值初始化、对象操作(size)、添加元素、下标操作
- class Sale_item
- {
- public:
- // 隐式使用string 的默认构造函数初始化 isbn
- Sale_item():price(0.0){}
- Sale_item(const string &book):isbn(book), price(0.0){}
- // 建议使用默认实参,将上述2个构造函数合并。如下:
- // Sale_item(const string &book = ""):isbn(book), price(0.0){}
- private:
- string isbn;
- double price;
- };
class Sale_item
{
public:
// 隐式使用string 的默认构造函数初始化 isbn
Sale_item():price(0.0){}
Sale_item(const string &book):isbn(book), price(0.0){}
// 建议使用默认实参,将上述2个构造函数合并。如下:
// Sale_item(const string &book = ""):isbn(book), price(0.0){}
private:
string isbn;
double price;
};
合成的默认构造函数
如果,类没有定义构造函数,编译器将会自动生成一个默认的构造函数。
但是,如果已经定义过构造函数(哪怕只有1 个), 编译器就不会再生成默认构造函数。
理由:因为一个类,在某种情况下,需要控制对象的初始化,则,该类很可能在所有情况下都需要控制。
合成的默认构造函数,的初始化规则,与变量的初始化规则相同。
类类型,使用各自的默认构造函数,来初始化
内置、复合类型,如:指针、数组,只对定义在全局作用域中的对象才初始化,
定义局部作用域中,则,内置、复合类型不初始化,处于未定义状态。
类通常,都应该定义一个默认构造函数
假设:NoDefault ,是一个类,它具有接受一个 string 实参的构造函数,
这种情况下,编译器,不会生成默认构造函数。
于是,
1、当我定义一个类 A,具有 NoDefault 类型的成员,则,
A 的所有构造器,都必须通过传递一个初始 string 来初始化 NoDefault 类型的成员
2、当我定义一个类 A,具有 NoDefault 类型的成员,则,
编译器将不会生成 A 的默认构造器。只能自己显示定义
3、NoDefault 类型,不能用作动态分配数组的元素类型。
- int *iArr = new int[10];
- // 上式可行,下式报错
- NoDefault *arr = new NoDefault[10];
int *iArr = new int[10];
// 上式可行,下式报错
NoDefault *arr = new NoDefault[10];
4、NoDefault 类型的静态分配数组,也必须为每个元素提供显示的初始化
5、如果有保存 NoDefault 对象的容器,如:vector,
则,容器的构造函数,不仅要提供容器大小,也要提供元素初始化式。
- // 这是一个函数声明,函数返回类型:Sales_item
- Sales_item myObj();
- //
- Sales_item myObj2;
- // 创建一个 Sales_item 对象,并用默认构造函数初始化
- Sales_item myObj3 = new Sales_item();
// 这是一个函数声明,函数返回类型:Sales_item
Sales_item myObj();
//
Sales_item myObj2;
// 创建一个 Sales_item 对象,并用默认构造函数初始化
Sales_item myObj3 = new Sales_item();
隐式类型转换
- class Sales_item
- {
- public:
- Sales_item(const string &book = ""):isbn(book), units_sold(0), revenue(0.0){}
- // explicit 只能用于,类内部的构造函数声明上,在类的定义体外部则不用重复它
- explicit Sales_item(istream &is);
- Sales_item();
- bool same_isbn(Sales_item item)
- {
- return item.isbn == isbn;
- }
- private:
- string isbn;
- int units_sold;
- double revenue;
- };
- // 错误: explicit 只能在类内部的构造函数声明上
- explicit Sales_item::Sales_item(istream &is)
- {
- /* ... */
- }
- /* ... */
- string null_book = "9-999-9999-9";
- Sales_item item_a = Sales_item("1-111-1111-1");
- // 以下会隐式调用构造函数,生成一个 Sales_item 对象,来进行比较
- // 但这种隐式转换,未必是我们真正想要的。
- // 为阻止这种隐式转换,可以在构造函数前,使用 explicit 关键字
- item_a.same_isbn(null_book);
- // 建议使用下面的方式,避免错误
- item_a.same_isbn(Sales_item(null_book));
class Sales_item
{
public:
Sales_item(const string &book = ""):isbn(book), units_sold(0), revenue(0.0){}
// explicit 只能用于,类内部的构造函数声明上,在类的定义体外部则不用重复它
explicit Sales_item(istream &is);
Sales_item();
bool same_isbn(Sales_item item)
{
return item.isbn == isbn;
}
private:
string isbn;
int units_sold;
double revenue;
};
// 错误: explicit 只能在类内部的构造函数声明上
explicit Sales_item::Sales_item(istream &is)
{
/* ... */
}
/* ... */
string null_book = "9-999-9999-9";
Sales_item item_a = Sales_item("1-111-1111-1");
// 以下会隐式调用构造函数,生成一个 Sales_item 对象,来进行比较
// 但这种隐式转换,未必是我们真正想要的。
// 为阻止这种隐式转换,可以在构造函数前,使用 explicit 关键字
item_a.same_isbn(null_book);
// 建议使用下面的方式,避免错误
item_a.same_isbn(Sales_item(null_book));
- // 没有定义构造函数、并且,全体数据成员都是 public 的类,
- // 可以采用,与数组元素相同的方式,来初始化成员
- // 但,还是推荐,使用构造函数
- struct Data
- {
- int ival;
- char *ptr;
- };
- Data val1 = {0, 0};
// 没有定义构造函数、并且,全体数据成员都是 public 的类,
// 可以采用,与数组元素相同的方式,来初始化成员
// 但,还是推荐,使用构造函数
struct Data
{
int ival;
char *ptr;
};
Data val1 = {0, 0};
友元,允许一个类,将自己的,非公有成员的访问,授权给,指定的类或者函数。
它只能出现在类定义的内部。通常,将所有的友元声明,成组地放到类定义的开始或者结尾。
- class Screen
- {
- public:
- typedef string::size_type index;
- private:
- int height;
- int width;
- // 友元不是 Screen的成员,
- // 它可以出现在 Screen 类定义体中的,任何地方。
- // 并且,不受访问控制(private、public)的影响
- friend class Window_Mgr;
- // 将,其他类的成员函数,设置为友元
- friend Window_Mgr& Window_Mgr::relocate(Screen::index, Screen::index, Screen&);
- };
- class Window_Mgr
- {
- public:
- Window_Mgr& relocate(Screen::index r, Screen::index c, Screen &s)
- {
- s.height += r;
- s.width += c;
- return *this;
- }
- private:
- };
class Screen
{
public:
typedef string::size_type index;
private:
int height;
int width;
// 友元不是 Screen的成员,
// 它可以出现在 Screen 类定义体中的,任何地方。
// 并且,不受访问控制(private、public)的影响
friend class Window_Mgr;
// 将,其他类的成员函数,设置为友元
friend Window_Mgr& Window_Mgr::relocate(Screen::index, Screen::index, Screen&);
};
class Window_Mgr
{
public:
Window_Mgr& relocate(Screen::index r, Screen::index c, Screen &s)
{
s.height += r;
s.width += c;
return *this;
}
private:
};
要将类的成员函数,设为友元,则这个类必须先定义
要将类 或者 非成员函数 设为友元,则,不需要预先声明。
(P398,例子,貌似有误)
全局对象,会破坏封装性,而,类中定义的 静态成员,则能保持很好的封装性。
static 数据成员,与类相关联,而不是与类的对象关联。
static 成员函数,没有 this 形参。
- class Account
- {
- public:
- void applyint(){ amount += amount * interestRate; }
- static double rate() { return interestRate; }
- static void rate(double);
- private:
- string owner;
- double amount;
- static double interestRate;
- static double initRate();
- // 例外,const 类型的静态数据成员,可以在类定义体中初始化
- // 但是,即使如此,也必须在外部,进行定义
- static const int period = 30;
- };
- // 外部定义,但此时,无须提供初始化式
- const int Account::period;
- // 内部已经声明为 static 了
- // 外部定义的时候,不需要再指定 static
- // static 不能声明为 const、也不能声明为 虚函数
- // 声明为 const 是承诺不修改该函数所属的对象,
- // 然而, static 函数,不属于任何对象,它只与类关联
- void Account::rate(double newRate)
- {
- interestRate = newRate;
- }
- // static 数据成员,必须在类定义体的外部定义(刚好一次)
- // 一旦成员名出现,static 成员的定义,就在类作用域中了
- // 因此,可以直接使用 私有成员函数 initRate
- double Account::interestRate = initRate();
- Account ac1;
- Account *ac2 = &ac1;
- double rate;
- rate = ac1.rate();
- rate = ac2->rate();
- rate = Account::rate();
class Account
{
public:
void applyint(){ amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
string owner;
double amount;
static double interestRate;
static double initRate();
// 例外,const 类型的静态数据成员,可以在类定义体中初始化
// 但是,即使如此,也必须在外部,进行定义
static const int period = 30;
};
// 外部定义,但此时,无须提供初始化式
const int Account::period;
// 内部已经声明为 static 了
// 外部定义的时候,不需要再指定 static
// static 不能声明为 const、也不能声明为 虚函数
// 声明为 const 是承诺不修改该函数所属的对象,
// 然而, static 函数,不属于任何对象,它只与类关联
void Account::rate(double newRate)
{
interestRate = newRate;
}
// static 数据成员,必须在类定义体的外部定义(刚好一次)
// 一旦成员名出现,static 成员的定义,就在类作用域中了
// 因此,可以直接使用 私有成员函数 initRate
double Account::interestRate = initRate();
Account ac1;
Account *ac2 = &ac1;
double rate;
rate = ac1.rate();
rate = ac2->rate();
rate = Account::rate();
- class Bar
- {
- public:
- private:
- // static 数据成员的类型,可以是该成员所属的类类型。
- static Bar mem1;
- Bar *mem2;
- // 错误
- Bar mem3;
- };
- class Screen
- {
- public:
- Screen& clear(char = bkground);
- private:
- // static 数据成员,可以作为默认实参。
- static const char bkground = '#';
- };