C++11(6):类

来源:互联网 发布:茶道入门软件 编辑:程序博客网 时间:2024/05/22 21:04
在成员函数中,我们可以修改this的属性,(this  是  指向非常量的常量指针)
std::string Sales_data::isbn(const Sales_data *const this);
成员函数可以随意使用成员变量,编译器先编译变量
读入操作会改变流的内容,一般来说执行输出任务的函数应尽量减少对格式的控制,这样可以由用户代码来决定是否换行
构造函数不能声明成const
编译器自己创建的构造函数叫合成的默认构造函数。
当我们定义了其他的构造函数  编译器不在合成默认构造函数,只有当类没有任何构造函数时,编译器才会自动生成默认构造函数
合成默认函数可能执行错误操作,含有内置类型或复合类型成员的累应该在类内部初始化这些成员,或者定义一个默认初始化函数
成员包含没有默认构造函数的类,无法合成默认构造函数
(还有其他情况)

在c++11中,如果我们需要默认构造函数可以写成,Sales_dsata() = default;
=default 可以放在函数内部(内联),也可以放在函数外部(非内联)
包含vector或string成员的类,其拷贝,赋值,销毁的合成版本可以正常使用
struct默认访问时public,class是private
最好在类定义带式或结束前的位置集中声明友元函数
友元的声明仅仅指定了访问权限,所以要在别的地方重新声明
typedef std::string::size_typpe   pos;
#denfine   N  10

将成员变量声明成 mutable 我们就可以再const成员函数内修改变量了
当我们提供一个类内初始值时,必须以 =   或花括号表示
一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用;
非常量版本对于常量是不可用的
多使用类内的内联私有小函数,使类设计更清楚,降低复杂程度,方便调试
每个类定义了唯一的类型,就算成员完全一样,两个类也不同
在类声明而未定义时,叫不完全类,使用有限:可以指向类的引用、指针,也可以声明(但不能定义)以不完全类型作为参数或返回值的函数
知道类被定义之后数据成员才能被声明成这种类类型,但是,类允许包含指向它自身类型的指针或引用

class Screen{
//Window_mgr::clear必须在Screen类之前声明
frinend void Window_mgr::clear(ScreenIndex);
//Screen类的剩余部分
};
我们要按下面的方式设计程序:
首先定义Window_mgr类,其中声明clear函数,但不能定义它,在clear使用Screen的成员之前必须先声明Screen
接下来定义Screen,包括对clear的友元声明
最后定义clear,此时它才可以使用Screen的成员。

类的非成员函数的声明不是必须在它们的友元声明前
友元声明不是真正的声明,所以友元声明过后,如果好使用的话   要进行真正的声明使函数可见
 
在函数的外部,函数的返回类型出现在函数名之前,返回类型位于作用域之外,因此
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s){};

对于类,首先,编译成员的声明,直到类全部可见后才编译函数体,在类声明中定义的函数体也是
所以函数体可以使用类中任何定义的名字,
在类中,如果成员使用了外层作用域的某个名字,而改名字代表一种类型,则类不能再之后重新定义该名字
类型名的定义一般出现在开始
在成员函数中如果有与成员变量一样的名字,函数中的将屏蔽成员变量,但是我们可以通过this  访问
在考虑全局作用域时,不仅有类前的作用,还有成员函数的之前的全局域

对于const  和引用的初始化应该采用初始化列表,因为随着构造函数一开始执行,初始化就完成了、
构造函数初始化列表只是用于说明初始化成员的值,而不限定初始化的具体顺序。
成员函数的初始化顺序与他们在类中定义的顺序一致,因此最好然初始化列表中的顺和变量定义的顺序一致
对于构造函数参数中有默认值时,实际上是提供了默认的构造函数的
委托构造函数:
class Sales_data {
public:
    sales_data(std::string s,unsigned cnt,double price):bookNo(s),units_sold(cnt),revenue(cnt*price){ }
    Sales_data():Sales_data(" ", 0 , 0){ }
    Sales_data(std::istream &is):Sales_data()  {read(is,*this);}
};
后两个就是委托构造函数,先执行的是受委托函数体中的代码,然后才将控制全交给委托函数
默认构造函数在变量定义是自动调用,不要显示的去调用默认构造函数(不要给默认构造函数后加括号)

当对象被默认初始化或值初始化时自动执行默认构造函数。
默认初始化在一下情况发生:
当我们在块作用域内不使用任何初始值定义一个非静态变量或数组时;
当一个类本身含有类类型的成员且使用的是合成默认构造函数
当类类型的成员没有在构造函数初始化列表中显示的初始化时。
值初始化发生在以下情况:
在数组初始化的过程中如果我们提供的初始值数量少于数组大小时
当我们不使用初始值定义一个局部静态变量时
当我们通过书写形如T()的表达式显示地请求初始化时
合成默认构造函数,如果存在类内值初始化,则用它初始化,否则使用默认初始化

能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则
就是当需要一个类类型时,我们可以使用一个别的类型(只有一个参数的构造函数中的类型)来转换
只允许一步类类型转换

抑制构造函数定义的隐式转换:我们可以通过将构造函数声明为explicit,只对有一个实参的构造函数有效
只能在直接初始化中使用explicit构造函数,不能在拷贝初始化中使用。
explicit的构造函数不会用于隐式转化过程,但是我们可以使用强制类型转换
item.combine(static_cast<Sales_data>(cin) );
在标准库中,
接受一个单参数的const char*的string构造函数不是explicit
接受一个容量参数的vector构造函数式explicit的

聚合类:所有成员都是public的,没有定义任何构造函数,没有类内初始值,没有基类,也没有virtual函数
struct Data{
    int  ival;
    string  s;
};
Data val1={ 0 , "Anna"} ;     //聚合类的初始化,顺序不能变,如果提供的参数少于变量,那么执行值初始化
对于字面值类型的类,可能含有constexpr函数成员,这样的成员必须符合constexpr函数的所有要求,它们是隐式const的
数据成员都是字面值类型的聚合类是字面值常量,如果一个列不是聚合类,但它符合下述要求,他也是一个字面值常量类:
数据成员都必须是字面值类型,
类必须至少含有一个constexpr构造函数。
如果一个数据成员含有类内初始值,则内置类型成员的初始值必须是一条常量表达式;或者 如果成员属于某种类类型,则初始这必须使用成员自己的constexpr构造函数
类必须使用析构函数的默认定义,该成员负责销毁类的对象                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              

构造函数不能使const的,但是,字面值常量类的构造函数可以是constexpr函数。事实上,一个字面值常量类必须至少提供一个constexpr构造函数,它可以声明成default(或者是删除函数的形式)否则,它必须既符合构造函数的要求(无返回语句)又符合constexpr函数的要求(只有返回语句),那么constexpr就是空的函数体了,
constexpr Debug(bool  b=true): hw(b),io(b),other(b){ }
constexpr构造函数必须初始化所有数据成员,初始值或者使用constexpr构造函数,或者是一条常量表达式
constexpr构造函数用于生成constexpr对象以及constexpr函数的参数或返回类型
constexpr Debug io_sub(false,true,false);//定义个Debug类类型的变量

我们通过在成员之前加上关键在static使得其与类关联在一起
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。
静态函数也不与任何对象绑定在一起,它们不包含this指针,因此,静态成员函数不能声明成const的,而且也不能再static函数体内使用this指针,这一限制适用于this的显示使用,也对调用非静态成员的隐式使用有效

我们使用作用域访问符::直接访问静态成员
虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、引用或指针来访问静态成员
对于成员函数不用使用作用域访问符就可直接访问静态成员

当在类的外部定义静态成员函数时,不能重复使用, 这个关键字只能出现在类内部
因为静态数据成员不属于类的任何一个对象,所以,它们并不是在创建类的对象时被定义的,它们不是由类的构造函数初始化的,一般,我们不能再类的内部初始化静态成员。必须在类的外部初始化每个静态成员,和全局变量一样,静态函数成员定义在任何函数之外。因此一旦定义就一直存在。
double Account::interestRate=initRate();  //定义并初始化
要想保证之定义一次,就把定义和别的非内联函数的定义放在一起

不应该在雷内初始化静态成员,但是我们可以为静态成员提供const整型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr,初始值必须是常量表达式,因为这些成员本来就是常量表达式,可以用到需要成了表达式的地方
//类内    
static  constexpr int period  = 30;
double daily_tbl[period];

即使在类内提供了一个初始值,通常也要在类外定义该成员,定义时不用提供初始值
constexpr int Account::period;

因为静态成员独立于任何对象。因此某些非静态非法,静态可用。
静态数据成员可以使不完全类型,特别,静态数据成员的类型可以就是它说属的类,对于非静态,只能声明所属类的指针或引用
我们可以用静态成员做默认实参,因为默认实参不能是局部变量
0 0