C++ primer 第三章 标准库类型

本章主要讲了标准库类型,其中主要从以下几个方面进行了说明。
第一:命名空间的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)、添加元素、下标操作

 

  1. class Sale_item
  2. {
  3. public:
  4. // 隐式使用string 的默认构造函数初始化 isbn
  5. Sale_item():price(0.0){}
  6. Sale_item(const string &book):isbn(book), price(0.0){}
  7. // 建议使用默认实参,将上述2个构造函数合并。如下:
  8. // Sale_item(const string &book = ""):isbn(book), price(0.0){}
  9. private:
  10. string isbn;
  11. double price;
  12. };
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 类型,不能用作动态分配数组的元素类型。

  1. int *iArr = new int[10];
  2. // 上式可行,下式报错
  3. NoDefault *arr = new NoDefault[10];
int *iArr = new int[10];

// 上式可行,下式报错
NoDefault *arr = new NoDefault[10];

4、NoDefault 类型的静态分配数组,也必须为每个元素提供显示的初始化
5、如果有保存 NoDefault 对象的容器,如:vector,
则,容器的构造函数,不仅要提供容器大小,也要提供元素初始化式。



  1. // 这是一个函数声明,函数返回类型:Sales_item
  2. Sales_item myObj();
  3. //
  4. Sales_item myObj2;
  5. // 创建一个 Sales_item 对象,并用默认构造函数初始化
  6. Sales_item myObj3 = new Sales_item();
// 这是一个函数声明,函数返回类型:Sales_item
Sales_item myObj();

// 
Sales_item myObj2;

// 创建一个 Sales_item 对象,并用默认构造函数初始化
Sales_item myObj3 = new Sales_item();


隐式类型转换

  1. class Sales_item
  2. {
  3. public:
  4. Sales_item(const string &book = ""):isbn(book), units_sold(0), revenue(0.0){}
  5. // explicit 只能用于,类内部的构造函数声明上,在类的定义体外部则不用重复它
  6. explicit Sales_item(istream &is);
  7. Sales_item();
  8. bool same_isbn(Sales_item item)
  9. {
  10. return item.isbn == isbn;
  11. }
  12. private:
  13. string isbn;
  14. int units_sold;
  15. double revenue;
  16. };
  17. // 错误: explicit 只能在类内部的构造函数声明上
  18. explicit Sales_item::Sales_item(istream &is)
  19. {
  20. /* ... */
  21. }
  22. /* ... */
  23. string null_book = "9-999-9999-9";
  24. Sales_item item_a = Sales_item("1-111-1111-1");
  25. // 以下会隐式调用构造函数,生成一个 Sales_item 对象,来进行比较
  26. // 但这种隐式转换,未必是我们真正想要的。
  27. // 为阻止这种隐式转换,可以在构造函数前,使用 explicit 关键字
  28. item_a.same_isbn(null_book);
  29. // 建议使用下面的方式,避免错误
  30. 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));


  1. // 没有定义构造函数、并且,全体数据成员都是 public 的类,
  2. // 可以采用,与数组元素相同的方式,来初始化成员
  3. // 但,还是推荐,使用构造函数
  4. struct Data
  5. {
  6. int ival;
  7. char *ptr;
  8. };
  9. Data val1 = {0, 0};
// 没有定义构造函数、并且,全体数据成员都是 public 的类,
// 可以采用,与数组元素相同的方式,来初始化成员
// 但,还是推荐,使用构造函数
struct Data
{
	int ival;
	char *ptr;
};
Data val1 = {0, 0};


友元,允许一个类,将自己的,非公有成员的访问,授权给,指定的类或者函数。
它只能出现在类定义的内部。通常,将所有的友元声明,成组地放到类定义的开始或者结尾。

  1. class Screen
  2. {
  3. public:
  4. typedef string::size_type index;
  5. private:
  6. int height;
  7. int width;
  8. // 友元不是 Screen的成员,
  9. // 它可以出现在 Screen 类定义体中的,任何地方。
  10. // 并且,不受访问控制(private、public)的影响
  11. friend class Window_Mgr;
  12. // 将,其他类的成员函数,设置为友元
  13. friend Window_Mgr& Window_Mgr::relocate(Screen::index, Screen::index, Screen&);
  14. };
  15. class Window_Mgr
  16. {
  17. public:
  18. Window_Mgr& relocate(Screen::index r, Screen::index c, Screen &s)
  19. {
  20. s.height += r;
  21. s.width += c;
  22. return *this;
  23. }
  24. private:
  25. };
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 形参。

  1. class Account
  2. {
  3. public:
  4. void applyint(){ amount += amount * interestRate; }
  5. static double rate() { return interestRate; }
  6. static void rate(double);
  7. private:
  8. string owner;
  9. double amount;
  10. static double interestRate;
  11. static double initRate();
  12. // 例外,const 类型的静态数据成员,可以在类定义体中初始化
  13. // 但是,即使如此,也必须在外部,进行定义
  14. static const int period = 30;
  15. };
  16. // 外部定义,但此时,无须提供初始化式
  17. const int Account::period;
  18. // 内部已经声明为 static 了
  19. // 外部定义的时候,不需要再指定 static
  20. // static 不能声明为 const、也不能声明为 虚函数
  21. // 声明为 const 是承诺不修改该函数所属的对象,
  22. // 然而, static 函数,不属于任何对象,它只与类关联
  23. void Account::rate(double newRate)
  24. {
  25. interestRate = newRate;
  26. }
  27. // static 数据成员,必须在类定义体的外部定义(刚好一次)
  28. // 一旦成员名出现,static 成员的定义,就在类作用域中了
  29. // 因此,可以直接使用 私有成员函数 initRate
  30. double Account::interestRate = initRate();
  31. Account ac1;
  32. Account *ac2 = &ac1;
  33. double rate;
  34. rate = ac1.rate();
  35. rate = ac2->rate();
  36. 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();

  1. class Bar
  2. {
  3. public:
  4. private:
  5. // static 数据成员的类型,可以是该成员所属的类类型。
  6. static Bar mem1;
  7. Bar *mem2;
  8. // 错误
  9. Bar mem3;
  10. };
  11. class Screen
  12. {
  13. public:
  14. Screen& clear(char = bkground);
  15. private:
  16. // static 数据成员,可以作为默认实参。
  17. static const char bkground = '#';
  18. };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值