1.类内部定义的函数默认为inline;
2.可以声明一个类而不定义它:
class Screen; //前向声明,此时Screen是一个不完全类型
不完全类型只能以有限方式使用,不能定义该类型的对象,只能定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数;
3.因为只有当类定义体完成后才能定义类,所以类不能具有自身类型的数据成员(只能是指向自身类型的指针或引用);
4.定义一个类,相当于定义了一个类型,之后可以定义该类型的对象;(一般而言)定义类型时不进行类型分配,而定义对象时,将为其分配存储空间;
5.const成员函数:在普通的非const成员函数中,this是一个指向类类型的const指针,即可以改变this所指向的对象的值,但不能改变this所保存的地址;在const成员函数中,this是一个指向const类类型的const指针,不能改变this所指向的对象,也不能改变this保存的地址;
*const成员函数不能调用非const成员函数:因为在调用过程中,const成员函数会把const的this隐式传递给非const成员函数,这样子把一个常量地址赋给一个变量地址是不允许的;
6.可变数据成员:
可将数据成员声明为mutable,它不能为const;const成员函数可以改变mutable成员;
7.如果返回类型使用由类定义的类型,必须使用完全限定名:
class Screen
{
public:
typedef std::string::size_type index;
index get_cursor() const;
private:
index cursor;
};
inline Screen::index Screen::get_cursor() const
{
return cursor;
}
8.基于const的重载:
在一个类中(比如Student类),print() const 和 print() 两个成员函数可以同时存在,因为它们的函数签名是不同的,print() const的隐藏参数是const Student ,而print()的隐藏参数是Student ;
9.构造函数:
构造函数可以被重载,每个对象只能(并且必须)调用所在类的其中一个构造函数;
构造函数不能声明为const:因为其工作是用来初始化对象;
9.1构造函数的初始化式
构造函数的初始化式只能在构造函数的定义而不是声明中指定;
//初始化列表
Sales_item::Sales_item(const string &book):
isbn(book), units_sold(0), revenue(0.0) {}
//无初始化列表
Sales_item::Sales_item(const string &book)
{
isbn = book;
units_sold = 0;
revenue = 0.0;
}
/* 区别:
* 初始化列表的版本是【初始化】数据成员;
* 另一个版本是先初始化,然后在函数体中对数据成员【赋值】。
* 构造函数两个执行阶段:1.初始化阶段;2.普通的计算阶段。
* 对于第二个版本,初始化阶段中,在局部作用域中这些成员不被初始化,
* 在全局作用域中初始化为0;
*/
为体现这一点的区别,我们看看哪些情况只能用初始化列表:
没有默认构造函数的类类型成员,以及const或引用类型的成员,都必须在构造函数初始化列表中初始化!
因为:我们可以初始化const对象或引用类型的对象,但是不能对它们赋值。而对于没有为类成员提供初始化式的情况,编译器会隐式使用其默认构造函数,当该类没有默认构造函数时,编译器的尝试将会失败。
**成员初始化的次序:成员被初始化的次序就是定义成员的次序,而与列表上的顺序无关!
class X {
int i;
int j;
public:
// undefined: i is initialized before j
// i先于j初始化,此时如果用j来初始化i,结果是未定义的
X(int val): j(val), i(j) { }
};
初始化式可以是任意表达式;
9.2默认构造函数
当一个类没有定义任何构造函数时,编译器才会自动生成一个默认构造函数;
使用默认构造函数时,注意以下区别:
Sales_item myobj(); //error, declares a function, not an object!
Sales_item myobj; //ok,使用默认构造函数
Sales_item myobj = Sales_item(); //ok,用一个匿名,空的对象来初始化myobj;
9.3构造函数定义的隐式转换
class Sales_data {
public:
Sales_data(const std::string &book = ""):
isbn(book), units_sold(0), revenue(0.0) { }
Sales_data(std::istream &is);
};
//same_isbn的参数类型应该为Sales_data,但是由于隐式转换,这里cin隐式转换为Sales_data类型(通过第二个构造函数),创建了一个临时的Sales_data对象,并传递给same_isbn,一旦函数结束,该对象就不能访问了,这可能导致错误。
item.same_isbn(cin);
为防止隐式转换,可添加explicit关键字:
class Sales_data {
public:
explicit Sales_data(const std::string &book = ""):
isbn(book), units_sold(0), revenue(0.0) { }
explicit Sales_data(std::istream &is);
};
**explicit关键字只能用于【类内部】的构造函数【声明】上。
通常,单形参构造函数应该为explicit,以避免错误,之后如果需要转换,可以显式进行:
item.same_isbn(Sales_data(cin));
10.static类成员
通常,非static数据成员存在于类类型的每个对象实例中,而static数据成员不同,它独立于该类的任意对象而存在,即每个static数据成员是类类型关联,不与对象实例关联;
static成员函数没有this形参(因此不能声明为const),它可以直接访问所属类的static成员,但不能直接使用非static成员;另外,static成员函数不能被声明为虚函数;
static成员遵循正常的公用/私有访问规则;
//假设类Account有一个 static double rate();成员
Account ac;
double rate;
rate = ac.rate();
rate = Account::rate();
如果static成员函数在类外部定义,则只需要在内部声明时指定static;
**注意,static数据成员在类中仅进行【声明】,它不通过类构造函数初始化,而应该在定义时初始化,它必须在类定义体【外部】定义(有且仅有一次),且定义时不能标示为static;
//定义
double Account::myStaticMem = initRate();
一个例外:只有初始化式是一个常量表达式,整型const static数据成员就可以在类的定义体中初始化:
class Account {
public:
static double rate() { return interestRate; }
static void rate(double);
private:
static const int period = 30;// period is a constant expression
double daily_tbl[period]; //ok
};
//但是数据成员仍然需要在类的定义体外定义!只是不需要再初始化了。
const int Account::period;
**static成员不是类对象实例的组成部分,它的类型可以是该成员所属类的类型:
class Bar {
public:
// ...
private:
static Bar mem1; // ok: static member can have incomplete type
Bar *mem2; // ok: pointer member can have incomplete type
Bar mem3; // error: data members must have complete type
};

6860

被折叠的 条评论
为什么被折叠?



