《C++Primer》 类

类,定义了一个新的类型和一个新的作用域。

1.类成员
每个类可以没有成员,也可以定义多个成员,成员可以是数据、函数或类型别名。
public部分定义的成员可被使用该类的所有代码访问;
private部分定义的成员只能被自己的类成员访问。
所有成员必须在类的内部声明,一旦类定义完成后,就没有任何方式可以增加成员了。

2.构造函数
创建一个类类型的对象时,编译器会自动使用一个构造函数来初始化该对象。
构造函数是一个特殊的、与类同名的成员函数,用于给每个数据成员设置适当的初始值。
构造函数一般应使用一个构造函数初始化列表,来初始化对象的数据成员:
Sales_item():units_sold(0), revenue(0.0) {}
构造函数初始化列表由成员名和带括号的初始化值组成,跟在构造函数的形参表之后,并以冒号开头。

3.成员函数
在类内部,声明成员函数是必需的,而定义成员函数是可选的。在类内部定义的函数默认为inline。
在类外部定义的成员函数必须指明他们是在类的作用域中。
成员函数有一个附加的隐含实参,将函数绑定到调用函数的对象:
trans.avg_price()
就是在调用名为trans的对象的avg_price函数。如果trans是一个Sales_item对象,则在avg_price函数内部对Sales_item类成员的引用就是对trans成员的引用。
可以将关键字const加在形参表之后,就可以将成员函数声明为常量:
double avg_price() const;
const成员不能改变其所操作的对象的数据成员。const必须同时出现在声明和定义中。

数据抽象和封装

接口和实现分离,即有了数据抽象。类设计者必须关心类是如何实现的,而使用该类的程序员仅需了解类的接口。
封装是一项将低层次的元素组合起来形成新的、高层次实体的技术。
函数是封装的一种形式:函数所执行的细节行为被封装在函数本身这个更大的实体中。
被封装的元素隐藏了它们的实现细节————可以调用一个函数但不能访问它所执行的语句。
同样,类也是一个封装的实体:它代表若干成员的聚集。
一个设计良好的类类型隐藏了实现该类型的成员。
标准库类型vector同时具备数据抽象和封装的特性。而数组在概念上类似于vector,但既不是抽象的,也不是封装的。

数据抽象强调不同层次不同目的看一个对象,而封装强调不能进入对象观察和操作他的内脏。。

在C++中,public实现了数据抽象,而private封装了类型的实现细节。
一个访问标号可以出现的次数通常没有限制。
在类的左花括号之后、第一个访问标号之前定义成员的访问级别,如果类是用struct定义的,则这些成员是公有的,如果类是用class定义的,则这些成员是私有的。
即 strut默认公有,class默认私有。

好的类设计者会定义直观和易用的类接口。让类的用户完全自然和便利地使用类,就像天生会喝水吃饭一样自然。

数据抽象和封装提供了两个重要优点:
避免类内部出现无意的、可能破坏对象状态的用户级错误。!!(用户造成的无意的但是是强破坏力的)当错误发生时,能把错误限定在一个小范围内进行检查。
随时间推移可以根据<需求改变>或<缺陷(bug)报告>来完善类实现,而无须改变用户级代码。

使用类型别名来简化类
类还可以定义自己的局部类型名字。如果为std::string::size_type提供一个类型别名:
Class Screen{
public:
    typedef std::string::size_type index;
private:
    std::string contents;
    index cursor;
    index height,width;
};
将index的定义放在类的public部分是因为希望用户使用这个名字。Screen类的使用者不必了解用string实现的底层细节。定义index来隐藏Screen的实现细节。

像非成员函数一样,成员函数也可以被重载。 成员函数只能重载本类的其他成员函数。类的成员函数和普通的非成员函数以及在其他类中声明的函数不相关,也不能重载它们。
重载的成员函数和普通函数应用相同的规则:两个重载成员的形参数量和类型不能完全相同。调用非成员重载函数所用到的函数匹配过程也应用于重载成员函数的调用。

class Screen {
public:
    typedef std::string::size_type index;
    char get() const { return contents[cursor]; }
    char get( index ht, index wd ) const;
private:
    std::string contents;
    index cursor;
    index height, width;
};
调用,
Screen myscreen;
char ch = myscreen.get();
ch = myscreen.get(0,0);

显式制定inline成员函数
在类内部定义的成员函数,例如不接受实参的get成员,将自动作为inline处理。
当它们被调用时,编译器将试图在同一行内扩展该函数。也可以显示地将成员函数声明为inline

最佳位置:把inline仅放在类外部函数的定义前,而不是类的public声明区。

类声明与类定义
在一个给定的源文件中,一个类只能被定义一次。
如果在多个文件中定义一个类,那么每个文件中的定义必须是完全相同的。
使用头文件保护符来保证即使头文件在同一文件中被包含多次,类定义也只出现一次。
前向声明
class Screen;
声明而不定义它,类Screen是一个不完全类型(incompete type),即已知Screen是一个类型,但不知道包含哪些成员。
不完全类型只能以有限方式使用。不能定义该类型的对象。只能用于:
1.定义指向该类型的指针及引用。
2.用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
在创建类的对象之前,必须完整地定义该类。必须定义类,而不只是声明类,这样编译器就会给类的对象预定相应的存储空间。
同样在使用引用或指针访问类的成员之前必须已经定义类。

如果该类型是不完全类型,那么数据成员只能是指向该类类型的指针或引用。
因为只有当类定义体完成后才算定义类,因此类不能具有自身类型的数据成员。
然而,只要类名一出现就可以认为该类已声明。因此,类的数据成员可以是指向自身类型的指针或引用:
class LinkScreen
{
    Screen window;
    LinkScreen *next;
    LinkScreen *prev;
};
类的前向声明一般用来编写相互依赖的类。
如:定义两个类X和Y,X中有一个指向Y的指针,Y中有一个X类型的对象。

类对象
一旦定义了类,就可以定义该类型的对象。定义对象时,将为其分配存储空间,但(一般而言)定义类型时不进行存储分配;

隐含的this指针
成员函数具有一个附加的隐含形参,即指向该类对象的一个指针。这个隐含形参命名为this,与调用成员函数的对象绑定在一起。
成员函数不能定义this形参,而是由编译器隐含地定义。
成员函数的函数体可以显示使用this指针,但不是必须这么做。如果对类成员的引用没有限定,编译器会将这种引用处理成通过this指针的引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值