类和对象的关系就像设计图和房子的关系——类十构建类的对象的“设计图”。正如一张设计图可以造出很多房子,却不可能住在设计图里面;我们不能直接使用类,但是可以由一个类实例化(创建)很多对象。
观察真实世界,随处都能看到对象(object)——人、动物、汽车等。这些对象都有共同点:
1. 它们都有属性:大小、形状、颜色等
2. 它们都有行为:如球的滚动、弹跳,人的行走、睡觉,车的加速、转弯等
C++中,对象由类实例化而成,所以可以认为对象包含了数据和函数,虽然实际上并非如此:
假如对一个类的类名或该类的一个对象进行sizeof运算,结果将只包含该类的数据成员的大小。
在C++等面向对象的语言中中,编程的重点在于类,即重点在于创建自己的用户自定义类型上
这些用户自定义类型称为类
一个类包含:
class GradeBook{
public:
void displayMessage(){
cout << "Welcome to the Grade Book!" << endl;
}
private:
string courseName;
};
GradeBook gb; gb.displayMessage();
成员访问说明符(public,private等)之后必须有冒号(:)
public表明该函数或数据十“公共课用的”,也就是说可以被程序中的其他函数或其他类的成员函数所调用(使用)
在成员访问说明符private之后声明的变量或者函数,只可以被声明他们的类的成员函数所访问,不能被类之外的函数或其他类的成员函数访问
- 识图通过myGradeBook.courseName之类的表达式访问数据成员courseName将导致编译错误
- 被某个类生命为友元的函数和类,可以访问该类的private成员
- 采用获取函数和设置函数来访问和操纵数据成员是一种良好的变成习惯
在我们创建一个对象的同时初始化数据成员,可以使用构造函数
实际上即便我们没有显式地定义一个构造函数,编译器也会隐式地创建一个默认的构造函数,这个函数不初始化类的数据成员,因此这些成员变量通常包含一个“垃圾”值,如-237538
因此我们最好自定义一个具有实参的构造函数
请注意以下几点:
class Time1{ Time1( int = 0, int = 0, int = 0 ) };
当对象撤销时,类的析构函数会被隐式调用,如离开对象所在的作用域时
实际上,析构函数本身并不释放对象占用的内存空间,它知识在系统收回对象的内存空间之前执行骚味工作,这样内存可以重新用于保存新的对象。
class A{
public:
A( int, string ); //constructor
~A(); //destructor
private:
int id;
string name;
};
/* 类的接口
GradeBook.h */
#include
using namespace std;
class GradeBook{
public:
GradeBook( string );
void setCourseName( string );
string getCourseName();
private:
string courseName;
};
/* 类的定义
GradeBook.cpp*/
#include
using namespace std;
#include "GradeBook.h"
//constructor
GradeBook::GradeBook(string name){
setCourseName(name);
}
void GradeBook::serCourseName(string name){
courseName = name;
}
string GradeBook::getCourseName(){
return courseName;
}
不细说
程序员可以用关键字const来指定对象是不可修改的,这样任何识图修改该对象的操作都将导致编译错误,如
const Time noon(12,0,0);
将对象声明为const有助于贯彻最小特权原则,甚至可以提高性能
使用const的方法为:
//const对象
const int hour;
//const函数
int getTime() const{
return hour;
}
我们在使用const来定义对象或成员函数的时候,应该注意以下几点:
1. 编译器不允许声明为const的成员函数修改对象,因此将修改对象的数据成员的成员函数定义为const将导致编译错误
2. const成员函数不得调用同一类同一实例的非const成员函数
3. const对象不得调用非const成员函数
4. 构造函数和析构函数都会修改对象,因此不允许对构造函数和析构函数进行const声明
所有的数据成员都可以用成员初始化器进行初始化,而const对象不能通过赋值来初始化,所以const数据成员和引用的数据成员必须使用成员初始化器进行初始化
成员初始化器的位置在构造函数的 参数列表和左花括号 之间,跟const类似,并用一个冒号(:)与参数列表隔开,初始化的形式为:数据成员名称和圆括号包含的初始化值,如下:
class Add{
public:
Add(int c=0,int i=0)
:count(c),
increment(i)
{
//empty
}
private:
int count;
const int increment;
};
组成即 一个类将其他类的对象作为成员
类类型的数据成员用成员初始化器的方法初始化
friend函数在类的作用域之外定义,但是拥有访问类的所有成员的权限,但它并不是成员函数
//friend函数的定义
class Count{
friend void setX( Count &, int ); //friend function
public:
Count():x(0){}
private:
int x;
};
void setX(Count &c,int val){ //友元函数并不是成员函数
c.x=val;
}
friend类
//friend类的声明
class A{
public:
friend class B; //friend class
};
友元的关系既不是对称的也不是传递的,比如:
A是B的友元,B是C的友元,那么不能说A是C的友元(不传递),或者B是A的友元(不对称)
每一个对象都可以使用一个称为this的指针来访问自己的位置,而this指针并不是对象本身的一部分,相反,this被当作一个隐式的参数传递给对象的每一个非static成员函数
//this指针的使用
class Test{
public:
Test(int=0);
void print() const;
private:
int x;
};
void Test::print() const{
cout << x <//隐式调用
cout << this->x <//箭头调用
cout << (*this).x <//圆点调用
}
//使用this达到的串联的函数调用
class Time{
public:
Time(int=0,int=0,int=0);
Time &setHour(int h){ hour=h; return *this; }
Time &setMinute(int m){ minute=m; return *this; }
Time &setSecond(int c){ second=s; return *this; }
private:
int hour;
int minute;
int second;
};
int main(){
Time t;
//串联的函数调用
t.setHour(18).setMinute(30).setSecond(22);
圆点运算符的结合是从左到右的,因此三个函数的运行顺序是从左到右的
}
C++允许程序员在程序中对任何内置的或用户自定义的类型控制的内存进行分配和释放,这称为动态内存管理,有运算符new和delete完成
//为一个对象分配内存空间,返回一个指向对象类型的指针
Time *timePtr;
timePtr = new Time;
//撤销一个动态分配的对象并释放空间
delete timePtr;
//动态分配的同时提供初始化值
double *ptr = new double(3.14); //基本类型
Time *timePtr = new Time(1,2,3); //自定义对象
//动态地分配数组
int *array = new int[10];
int n = 7;
int *Array = new int[n];
//释放动态分配的数组的内存
delete [] array;
delete [] Array;
类的每个实例对象都格子拥有类的所有数据成员的一份副本,但是static成员例外,它的一份副本是被类的所有对象共享的
class Student{
public:
Student(string n){ allStu++; name=n; }
static int getStudent(){ return allStu; }
private:
string name;
static int allStu; //int类型的static成员数据可以在class内定义
};
int Student::allStu = 0;
int main(){
//没有类的实例的时候,该如何调用static函数
cout<< Student::getStudent()<< endl;
Student *jack=new Student("jack");
Student *tom=new Student("tom");
//两者结果一样
cout<< jack->getStudent()<< endl;
cout<< tom->getStudent()<< endl;
}
Reference: