首先我们举一个很常见的例子:钟表,时钟类的定义如下:
class Clock
{
public:
void SetTime(int newH,int newM,int newS);
void ShowTime();
private:
int hour,minute,second;
};
这里,封装了时钟的数据和行为,分别称为Clock类的数据成员和函数成员,定义类的语法形式如下:
class 类名称
{
public:
外部接口;
protected:
保护型成员;
private:
私有成员;
};
其中public, protected,private分别表示对成员的不同访问权限。
Notes:在类中可以声明函数的原型,函数的实现可以在外部。
类的成员包括数据成员以及函数成员,分别描述问题的属性以及行为。
对类成员访问权限的控制,是通过设置成员的访问控制属性而实现的,访问属性有一下3种:
公有类型(public)、私有类型(private)和保护类型(protected)。
公有类型成员定义了类的外部接口。公有成员用public关键字声明,在类的作用域外只能访问类的共有成员。对于时钟的例子,外部只能调用SetTime()和ShowTime()这两种公有类型。
在关键字private后面声明的就是类的私有成员。如果私有成员紧接着类名称,则关键字private可以被省略。私有成员只能被本类的成员函数访问,来自类外部的任何访问都是非法的。对于时钟的例子,hour、minute和second都是私有成员。
保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对产生的新类影响不同(本篇文章不做探究)
Notes:一般情况下,一个类的数据成员都应该声明为私有成员,这样,内部数据结构就不会对该类以外的其余部分造成影响。
Notes:在书写时通常习惯将公有类型放在前面,这样便于阅读,因为它们是外部访问时所要了解的。
Notes:在类的定义中,修饰访问属性的关键字可以出现多次。但是一个成员只能具有一种访问属性。例如:
class Clock
{
public:
void SetTime(int newH,int newM,int newS);
private:
int hour,minute,secondl
public:
void ShowTime();
};
类的成员函数描述的是类行为,例如时钟的SetTime()和ShowTime()。成员函数是程序算法的实现部分,是对封装的数据进行操作的方法。
函数的原型声明要写在类体中,原型说明了函数的参数表和返回类型。而函数的具体实现是可以写在类定义之外的。与普通函数不同的是,实现成员函数时要指明类的名称,具体形式为:
返回值类型 类名::函数成员名(参数表)
{
//函数体
}
类的成员函数也可以有默认形参值,其调用规则与普通函数相同,类成员函数的默认值,一定要写在类定义中,而不能写在类定义之外的函数实现中,例如:
class Clock
{
public:
void SetTime(int newH= 0,int newM = 0,int newS = 0);
....
};
这样,如果调用函数时没有给出实参,就会按照默认按照默认形参值将时钟设置到了0点。
一个类的大小,实际就是该类中"成员变量"之和,当然也要内存对齐,例如:
#include
using namespace std;
class A1
{
public:
void Fun1()
{}
private:
int a,b;
};
class A2
{
public:
void Fun2()
{}
};
class A3
{};
int main()
{
std::cout<<"A1 = "<< sizeof(A1)<<endl;
std::cout<<"A2 = "<< sizeof(A2)<<endl;
std::cout<<"A3 = "<< sizeof(A3)<<endl;
return 0;
}
A1 = 8,A2 = 1,A3 = 1;
Notes:空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
我们先看一段代码:
using namespace std;
class Clock
{
public:
void SetTime(int newH = 0,int newM = 0,int newS = 0)
{
hour = newH;
minute = newM;
second = newS;
}
void ShowTime()
{
}
private:
int hour,minute,second;
};
int main()
{
Clock myclock_1,myclock_2;
myclock_1.SetTime(12,12,12);
myclock_2.SetTime(0,0,0);
myclock_1.ShowTime();
myclock_2.ShowTime();
return 0;
}
那么思考这样一个问题:Clock类中有SetTime()和ShowTime()两个函数,函数体中没有关于不同对象的区分,那么为何当myclock_1调用SetTime()函数时,函数是怎么知道应该设置myclock_1对象,而不是myclock_2对象呢?
C++中通过引入this指针解决上上述问题:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象,在函数体中所有成员变量的操作都是通过this指针去访问,用户不需要去传递,编译器自动完成。
Notes:
class A1
{
public:
void Fun(int a)
{
b = a;
this -> b = a;
(*this).b = a;
}
private:
int b;
};
上述3种表示方式是等价的。
Notes:this指针只能在类的成员函数中调用,第一个成员函数的默认参数为:*T const register this , 如: class A{public: int func(int p){}}; 其中,func的原型在编译器看来应该是: int func(A const register this, int p);*它表示当前函数的地址。this指针一般放在成员函数的第一个参数列表中。
1.this指针存在哪里?
答:编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。
2.this指针可以为空吗?
答: 可以为空,当调用函数时,如果函数内部不需要使用到this,也就是不需要通过this指向当前对象并对其进行操作时才可以为空。
3.this指针是什么时候创建的?
答:this在成员函数的开始执行前构造的,在成员的执行结束后清除。
4.this指针如何访问类中变量的? 如果不是类,而是结构的话,那么,如何通过结构指针来访问结构中的变量呢?
答:在C++中,类和结构的区别是:类的成员默认是private,而结构是public。 this是类的指针,如果换成结构,那this就是结构的指针了。
如果将类看作是一个自定义的类型,那么类的对象就可以看作
是该类型的变量。声明一个对象和声明一个一般变量相同,采用以下的方式:
类名 对象名;
例如:
Clock myclock;
就声明了一个时钟类型的对象myclock。
定义了类及其对象,就可以访问对象的成员,这种访问方式采用的是“ . ”操作符,访问数据的一般形式为:
对象名.数据成员名
调用函数成员的一般形式为:
对象名.函数成员名(参数表)
例如,访问类Clock的对象myclock的函数成员ShowTime()的方式如下:
myclock.ShowTime()
在类的外部只能访问到类的公有成员,在类的成员函数中,可以访问到类的全部成员。