类 - 3C++ Primer 学习笔记
[cpp]
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 类型,不能用作动态分配数组的元素类型。
[cpp]
int *iArr = new int[10];
// 上式可行,下式报错
NoDefault *arr = new NoDefault[10];
4、NoDefault 类型的静态分配数组,也必须为每个元素提供显示的初始化
5、如果有保存 NoDefault 对象的容器,如:vector,
则,容器的构造函数,不仅要提供容器大小,也要提供元素初始化式。
[cpp]
// 这是一个函数声明,函数返回类型:Sales_item
Sales_item myObj();
//
Sales_item myObj2;
// 创建一个 Sales_item 对象,并用默认构造函数初始化
Sales_item myObj3 = new Sales_item();
隐式类型转换
[cpp]
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));
[cpp]
// 没有定义构造函数、并且,全体数据成员都是 public 的类,
// 可以采用,与数组元素相同的方式,来初始化成员
// 但,还是推荐,使用构造函数
struct Data
{
int ival;
char *ptr;
};
Data val1 = {0, 0};
友元,允许一个类,将自己的,非公有成员的访问,授权给,指定的类或者函数。
它只能出现在类定义的内部。通常,将所有的友元声明,成组地放到类定义的开始或者结尾。
[cpp]
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 形参。
[cpp]
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();
[cpp]
class Bar
{
public:
private:
// static 数据成员的类型,可以是该成员所属的类类型。
&
补充:软件开发 , C++ ,