类 - 3C++ Primer 学习笔记

来源:岁月联盟 编辑:猪蛋儿 时间:2012-11-15

[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 数据成员的类型,可以是该成员所属的类类型。 
    static Bar mem1; 
    Bar *mem2; 
 
    // 错误 
    Bar mem3;    
}; www.2cto.com
class Screen 

public: 
    Screen& clear(char = bkground); 
private: 
    // static 数据成员,可以作为默认实参。 
    static const char bkground = '#'; 
};