一、变量和类的生命周期
变量的生存期是指变量所占据的内存空间由分配到释放的时期。变量有效的范围称为其做用域。全局变量是程序中定义在全部函数(包括main函数)以外的任何变量,其做用域
是程序从变量定义到整个程序结束的部分。这意味着全局变量能够被全部定义在全局变量以后的函数访问。全局变量及静态变量分配的空间在全局数据区,它们的生存期为整个程序的执行期间。
⚫ 而局部变量,如在函数内或程序块内说明的变量,被分配到局部数据区,如栈区等。这种分配是临时的,一旦该函数体或程序块运行结束,所分配的空间就会被撤销。局部变量的生存期从被说明处开始,到所在程序块结束处结束。
⚫ 对于静态变量,若是没有进行初始化,系统会自动初始化为0。局部变量若是没有进行初始化,则其值是不肯定的。
⚫ 使用new运算符建立的变量具备动态生存期。从声明处开始,直到用delete运算符释放存储空间或程序结束时,变量生存期结束。类的对象在生成时调用构造函数,在消亡时调用析构函数,在这两个函数调用之间便是对象的生存期。数组
二、在类中,也可使用const关键字定义成员变量和成员函数,甚至是类的对象。由关键字const修饰的类成员变量称为类的常量成员变量。类的常量成员变量必须进行初始化,并且只能经过构造函数的成员初始化列表的方式进行。使用const修饰的函数称为常量函数。定义类的对象时若是在前面添加const关键字,则该对象称为常量对象。定义常量对象或常量成员变量的通常格式以下:
const 数据类型 常量名=表达式;
⚫ 定义常量函数的格式以下:类型说明符 函数名(参数表)const;
⚫ 在对象被建立之后,其常量成员变量的值就不容许被修改,只能够读取其值。对于常量对象,只能调用常量函数。总之,常量成员变量的值不能修改,常量对象中的各个属性值均不能修改。
⚫ 不能经过常量对象调用普通成员函数 const Person person;person.getName();//错误的函数
当生成封闭类的对象并进行初始化时,它包含的成员对象也须要被初始化,须要调用成员对象的构造函数。在定义封闭类的构造函数时,须要添加初始化列表,指明要调用成员对象的哪一个构造函数。在封闭类构造函数中添加初始化列表的格式以下:
封闭类名::构造函数名(参数表): 成员变量1(参数表),成员变量2(参数表),…{…}
初始化列表中的成员变量既能够是成员对象,也能够是基本数据类型的成员变量。对于成员对象,初始化列表的“参数表”中列出的是成员对象构造函数的参数(它指明了该成员对象如何初始化)。
先调用成员对象的构造函数,再调用封闭类对象的构造函数。测试
二、封闭类的复制构造函数
若是封闭类的对象是用默认复制构造函数初始化的,那么它包含的成员对象也会用复制构造函数初始化。this
//成绩类 class Course{ public: int id; string name; Course(); Course(Course &course); Course(int id,string name); }; Course::Course(Course &course){ cout << "Course 复制构造函数" << endl; this->id=course.id; this->name=course.name; } Course::Course(int id,string name){ this->id=id; this->name=name; cout << "Course 普通构造函数" << endl; }; //学生类 class Student{ public: int id; string name; //学生类中包含课程(Course),Student 称为封闭类 Course course; Student(int id,string name,int cId,string cName); void show(); }; Student::Student(int id,string name,int cId,string cName):id(id),name(name),course(cId,cName){ cout << "Student 普通构造函数" << endl; } void Student::show(){ cout << "name:" << this->name <<" course:" << this->course.name<< endl; } int main(){ Student student(1,"小米",1,"数学"); student.show(); Student student2(2,"美团",1,"C++"); student2.show(); }
C++语言规定,当调用一个成员函数时,系统自动向它传递一个隐含的参数。该参数是一个指向调用该函数的对象的指针,称为this指针,从而使成员函数知道对哪一个对象进行操做。
⚫ C++规定,在非静态成员函数内部能够直接使用this关键字,this就表明指向该函数所做用的对象的指针。
⚫ 在通常状况下,在不引发歧义时,能够省略“this->”,系统采用默认设置。
⚫ 静态成员是类具备的属性,不是对象的特征,this表示的是隐藏的对象的指针,因此静态成员函数没有this指针。spa
void Person::setName(string name){ this->name=name; } string Person::getName(){ return this->name; } void Person::setId(int id){ this->id=id; } int Person::getId(){ return this->id; }
一、同一类的对象之间能够相互赋值,
如语句:Point A,B; A.Setxy(25,55); B=A;
二、可使用对象数组,
如语句:Point A[3]; 定义数组A能够存储3个Point类的对象。
三、也可使用指向对象的指针,使用取地址运算符&将一个对象的地址置于该指针中,
如语句: Point * p=&A; p->Display();
四、对象能够用做函数参数。
若是参数传递采用传对象值的方式,会在传值过程当中产生副本,即临时对象,因此在被调用函数中对形参所做的改变不影响调用函数中做为实参的对象。
若是采起传对象的引用(传地址)的方式,当形参对象被修改时,相应的实参对象也将被修改。若是采用传对象地址值的方式,则使用对象指针做为函数参数,效果与传对象的引用同样。
C++推荐使用对象的引用做为参数传递,由于这样不会产生副本(即临时对象),在程序执行时不用调用构造函数,可直接进入函数体执行语句,在函数结束后,也不用调用析构函数析构临时对象。如想避免被调用函数修改原来对象的数据成员,可以使用const修饰符。设计
它们的原型声明分别为:print(Point),print(Point&),print(Point *)。
对于对象A,print(&A)调用的是原型为print(Point *)的函数形式。
另外,函数重载不能同时采用如上3种同名函数,由于函数使用的参数为对象或对象引用时,编译系统没法区别这两个函数,重载只能选择其中的一种。指针
使用类的权限
①类自己的成员函数可使用类的全部成员(私有和公有成员)。
②类的对象只能访问公有成员函数。例如输出x只能使用A.Getx(),不能使用A.x。
③其余函数不能使用类的私有成员,也不能使用公有成员函数,它们只能经过定义类的对象为本身的数据成员,而后经过类的对象使用类的公有成员函数。
④虽然一个类能够包含另一个类的对象,但这个类也只能经过被包含的类的对象使用那个类的成员函数,经过成员函数使用数据成员。person 是 student的成员,student不能直接操做person中的属性,只能 Student.person.成员的方式来操做person中的成员code
class Person{ public: int id; string name; }; class Student{ public: Person person; }
类不是内存中的物理实体,只有当使用类产生对象时,才进行内存分配,这种对象创建的过程称为实例化。
类必须在其成员使用以前先进行声明。然而,有时也能够在类没有彻底定义以前就引用该类,此时将类做为一个总体来使用,如声明全局变量指针:对象
class MembersOnly; //不彻底的类声明 MembersOnly * club; //定义全局变量类指针 Void main(){… 函数体} //主函数 class MembersOnly{…函数体}; //彻底定义该类
不彻底声明的类不能实例化,不然会编译出错;不彻底声明仅用于类和结构,企图存取没有彻底声明的类成员,也会引发编译错误。blog
尽管类的目的是封装代码和数据,它也能够不包括任何声明,如:class Empty{ }; 这种空类没有任何行为,但能够产生空类对象。
在开发大的项目时,须要在一些类尚未彻底定义或实现时进行先期测试,定义空类可保证代码能正确被编译,从而容许先测试其中的一部分。此时常给空类增长一个无参数构造函数,以消除强类型检查的编译器产生的警告。如
class Empty{
public:Empty(){ }
};
①声明类时所使用的一对花括号造成类做用域,在类做用域中声明的标识符只在类中可见,如:class example { int num; } ;
int i=num; //定义整型数i,并用num赋值;错误,由于num在类外并无定义,因此在此不可见
int num; //从新定义整型数num;正确,由于此num是从新定义的一个整型数,与类中说明的数据成员num具备不一样的做用域
②若是某成员函数的实现是在类定义以外给出的,则类做用域也包含该成员函数的做用域,所以,当在该成员函数内使用一个标识符时,编译器会先在类定义域中寻找,以下例:
class Myclass { int number; //定义属于类Myclass的整型数number public: void set(int); }; int number; //这个number不属于类Myclass void Myclass::set(int i){ number=i; //使用的是类Myclass中的标识符number };
③类中的一个成员名能够经过使用类名和做用域运算符来显式的指定,称为成员名限定,例如: void Myclass::set(int i){ Myclass::number=i; //显示指定访问Myclass类中的标识符number }④在程序中,对象的生存期由对象说明来决定;类中各数据成员的生存期由对象的生存期决定,随对象存在和消失。⑤使用struct关键字设计类与class相反,struct的默认控制权限是public,通常不用struct设计类,而是用struct设计只包含数据的结构,而后用这种结构做为类的数据成员。