类的一些笔记

c++最初的一个设计焦点就是能定义使用上像内置类型一样自然的类类型

每个类实际上都定义了一个新的类型,类型名就是类名。需要使用头文件来访问我们为自己的应用程序所定义的类。

成员函数是定义为类的一部分的函数,有时候也被称为方法。访问成员函数时使用点运算符(.),我们使用调用运算符(())来调用函数。

类的基本思想是数据抽象封装。数据抽象是依赖于接口和实现的分离编程技术,类的接口包括了用户所能执行的操作,类的实现包括类的数据成员、负责接口实现的函数体,以及定义类所需的各种私有函数。封装实现了类的接口和实现的分离,封装后用户只能使用接口而无法访问实现部分。

类要想实现数据抽象和封装,需要首先定义一个抽象数据类型。(自定义数据结构)这时候就需要定义一些操作以供用户使用,然后就可以封装它的数据成员了。

成员函数的声明必须在类的内部,它的定义则既可以在类的内部也可以在类的外部。作为接口组成部分的非成员函数它们的定义和声明都在类的外部。

成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象。因为this的目的总是指向“这个”对象,所以是个常量指针,我们不允许改变this中保存的地址。默认情况下this的类型是指向类类型非常量版本的常量指针。我们知道,要想存放常量对象的地址,只能使用指向常量的指针,这就意味着默认情况下的this不能绑定到一个常量对象上,c++允许把const关键字放在成员函数的参数列表后面紧跟在参数列表后面的const表示this是一个指向常量的指针。像这样使用const的成员函数被称作常量成员函数。常量成员函数不能改变调用它的对象的内容。std::string isbn() const {return bookno;} 紧跟参数列表之后的const关键字的作用是修改隐式this指针的类型,this的类型是sales_data *const。

构造函数的任务就是初始化对象的数据成员,无论何时只要有类的对象被创建,就会执行构造函数。构造函数的名字和类名相同,不能被声明成const。构造函数初始值列表是成员名字的一个列表,每个名字后面紧跟括号括起来的成员初始值,不同成员的初始值通过分号分开。当摸个数据成员构造初始值列表忽略时,他将以与默认构造函数相同的方式隐式初始化。

类可以在它的第一个访问说明符之前定义成员,对于这种成员的访问限制依赖于类定义的方式。如果使用struct关键字,定义在第一个访问说明符之前的成员是public,相反,如果用class,这些成员就是private。

友元的声明只能出现在类定义的内部,但这仅仅指定了访问的权限,而非一个通常意义上的函数声明,如果我们希望类的用户能够调用摸个友元函数,我们就必须在友元声明之外再专门对函数进行一次声明。

类还可以自定义某种类型在类中的别名。可以用typedef和using。

定义在类内部的成员函数是自动inline的,也可以在类的外部用inline关键字修饰函数,内联函数的作用是减少调用函数产生的开销。

成员函数也可以重载。

可以通过在变量的声明中加入mutable关键字,则该成员是可变值,任何成员函数,包括const函数在内都能改变它的值。

当我们提供一个类内初始值时,必须以符号=或者花括号表示。

返回*this,返回引用的函数是左值意味着直接返回对象本身,而非对象副本。

即使两个类的成员列表完全一致,他们也是不同的类型。我们可以把类名作为类型的名字使用,从而直接指向类类型,或者我们也可以把类名跟在关键字class或struct后面。

1.类可以把其他类定义成友元,也可以把其他类的成员函数定义成友元,友元函数能定义在类的内部,这样的函数是隐式内联的。如果一个类指定了友元类,则友元的成员函数可以访问此类半口非公有成员在内的所有成员。友元关系不存在传递关系。2.令成员函数成为友元,当一个成员函数声明成友元时,必须明确指出还成员函数是属于哪个类的,步骤是先定义被声明为友元成员函数的类,其中声明这个成员函数,但不能定义它,在成员函数使用声明友元的类的成员之前必须声明该类。接下来定义声明友元的类,包括对友元成员函数的声明,最后定义该成员函数,此时他才可以使用声明友元的类的成员。

重载函数是不同的函数,一个类想把一种重载函数声明成它的友元需要对每一个分别声明。

首先,编译成员的声明,直到类全部可见后才编译函数体。所以类中的函数体能够使用类中定义的任何成员名字。如果某个成员的声明使用了类中尚未出现的名字,则编译器将会在定义该类的作用于中继续查找。如果成员使用了外层作用域的某个名字,而该名字代表一种类型,则类不能再之后重新定义该名字。

不要把成名字作为参数或者其他局部变量使用。

如果成员是const、引用、或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些函数提供初值。

成元的初始化顺序与他们再累中定义的出现顺序一致。

可以通过在构造函数前加explicit来阻止隐式转换,关键字explicit只对一个实参的构造函数有效,需要多个实参的构造函数不能用于执行隐式转换。所以无需用该关键字。只能在类内声明时使用,在类外定义时不应重复。explicit构造函数只能用于直接初始化,不能执行拷贝初始化。接受一个但参数的const char*的string构造函数不是explicit,接受一个容量函数的vector构造函数是explicit。

类的静态成员,直接跟类相关,而不是跟类的各个对象保持关联。必须在类的外部定义和初始化每个静态类成员,静态数据成员定义在任何函数之外,将一直存在于程序的整个生命周期中,和其他成员的定义一样,静态数据成员 的定义也可以访问类的私有成员。静态成员和普通成员的的区别是静态成员可以使不完全类型,另一个区别是静态成员作为默认实参。

构造函数后面不要加“;”。

// pointer to classes example
#include <iostream>
using namespace std;

class Rectangle {
  int width, height;
public:
  Rectangle(int x, int y) : width(x), height(y) {}
  int area(void) { return width * height; }
};

int main() {
  Rectangle obj (3, 4);
  Rectangle * foo, * bar, * baz;
  foo = &obj;
  bar = new Rectangle (5, 6);
  baz = new Rectangle[2] { {2,5}, {3,6} };
  cout << "obj's area: " << obj.area() << '\n';
  cout << "*foo's area: " << foo->area() << '\n';
  cout << "*bar's area: " << bar->area() << '\n';
  cout << "baz[0]'s area:" << baz[0].area() << '\n';
  cout << "baz[1]'s area:" << baz[1].area() << '\n';       
  delete bar;
  delete[] baz;
  return 0;
}   

   1.类成员定义时不允许被初始化,因为类仅仅是一个类型,而没有空间分配。如果在构造函数中初始化也只是产生了临时变量,要初始化类成员应该使用冒号语法,用冒号引出构造函数的调用表(初始化列表)用构造参数类表中说明的参数去调用构造函数。

   2.组合类的概念就是:指在一个类的数据成员中含有一个或多个类的对象,拥有这样结构的类就叫组合类。这种以数据成员身份出现的类对象就叫子对象。

   3.继承和组合都可以实现一个类重用另一个类的行为功能,那么如何选择用组合类还是用继承?
当B与A属于同一类的范畴,并且B"is a kind of"A,一般应该把B设计为“继承”A;而如果B与A不属于同一类范畴,但是B"is a part of"A,并且A需要使用B的功能,这种情况应该设计为由B“组合出”A。

   4.组合类中的构造函数,当一个类既是组合类又是派生类,它在创建对象时,系统对构造函数的调用顺序有相应的规定:
最先调用基类的构造函数,初始化基类的数据成员;然后调用子对象所在类的构造函数,初始化子对象的数据成员;最后调用本类的构造函数,初始化新增数据成员。
   组合类中的析构函数当对象消亡时,系统对析构函数的调用顺序为:
最先调用本类的析构函数;然后调用子对象所在类的析构函数;最后调用基类的析构函数。

   5.这里我们首先要明白下面几点。
类的一个特征就是封装,public和private作用就是实现这一目的。所以:用户代码(类外)可以访问public成员而不能访问private成员;private成员只能由类成员(类内)和友元访问。
类的另一个特征就是继承,protected的作用就是实现这一目的。所以:protected成员可以被派生类对象访问,不能被用户代码(类外)访问。
继承中的特点:
先记住:不管是否继承,上面的规则永远适用!有public, protected, private三种继承方式,它们相应地改变了基类成员的访问属性。
1.public继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:public, protected, private
2.protected继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:protected, protected, private
3.private继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:private, private, private
但无论哪种继承方式,上面两点都没有改变:
1.private成员只能被本类成员(类内)和友元访问,不能被派生类访问;
2.protected成员可以被派生类访问。
总结:
public:     能类外,  能类内,  能派生
protected:不能类外, 能类内,  能派生
private:  不能类外,  能类内,不能派生

   6.在类外定义成员函数用双冒号::,调用成员函数用指针->。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值