目录
隐藏的this指针
● 对于类的非静态成员,每一个对象都有自己的一份拷贝, 即每个对象都有自己的数据成员, 不过成员函数却是每个对象共享的。 那么调用共享的成员函数是如何区分自己的的数据成员呢,答案就是通过类中隐藏的this 指针。
● this 指针是隐含在每个类成员函数中的指针, 其指向正在操作此函数的类对象,其类型为当前类类型的指针类型,在const函数中, 为当前类类型的const指针类型。 this指针的作用域是在类内部, 当在类的非静态成员函数中访问类的非静态成员时, 编译器会自动将对象本身的地址作为一个隐含参数传递给函数。
● 注意: 类的静态成员函数中没有this指针
void func(void *p, int val);
class A
{
public:
int getA()
{
return a;
}
void setA(int val);
friend void func(void *p, int val);
private:
int a;
};
void func(void *p, int val)
{
A *pp = (A*)p; 得到对象指针
pp->a = val;
}
void A::setA(int val)
{
func(this, val); 调用全局函数,this 表示当前对象指针
}
int main()
{
A aa;
aa.setA(500);
int x = aa.getA();
cout << "输出x的值:" << x << endl;
system("pause");
return 0;
}
在调用函数func时第一个参数是this 指针, 表明将对象aa 的指针传入 func中,然后通过对象aa 改变其中的成员变量a的值。
通过对象aa 调用setA() 函数, 在该函数的内部,this指针持有aa 对象的地址。 以这样的方式, 成员函数可以访问对象内的任何元素。
this指针将作为隐藏的参数传递给每个成员函数, 且this指针通常是函数接受的第一个参数、其后是已声明的其他参数, 假定setA() 函数如下:
void setA(A *this,int val);
在调用该函数时,应该这样:
aa.setA(&aa,500);
● 隐藏的this 指针应该注意的问题
this指针不能被修改,绝不能给它赋值,需要在成员函数内部修改this指针的情况很少见
什么时候必须使用this指针
利用this指针去除歧义的时候。
当我们希望返回对调用某函数的对象的引用时, 必须使用*this。
另一种情况是: 我们希望获得对象的地址,也必须显式使用this 指针。
静态数据成员
● 有时可能需要一个或多个公共的数据成员能够被类的所有对象共享,或者在程序的任意点需要统计已创建的特定类类型对象的数量。 在C++中,可以定义static数据成员和static成员函数用于解决同一个类的不同对象之间数据和函数共享的问题,
用一个类的不同对象的静态成员使用同一个内存空间, 但是又不会破坏封装。
● 通常, 非static 数据成员存在于类类型的每个对象中, 不像普通的数据成员,static 数据成员独立于该类的任意对象而存在; 每个static数据成员是与类关联的对象,并不与该类的对象关联。
类还可以定义static 成员函数,该函数没有this形参,可以直接访问所属类的static 成员, 但不能直接使用所属类的非static 成员。
● 使用类的static 成员好处有:
有利于类的封装, 可以把static成员定义为私有,防止外部访问。
static 成员与特定的类相关联。,在外部使用必须使用类名字做前辍, 程序更加清晰。
static成员的名字是在类的作用域中,可以避免命名冲突。
● 静态数据成员可以被所有类的对象共享。这就意味着无论定义多少个类对象, 每个类的只有一个静态数据成员的拷贝,从而实现同类对象之间的数据共享。
如果某一个对象修改了static数据成员,其他对象的static数据成员也将被改变。 声明一个静态数据变量添加前辍关键字static。
● 非静态数据成员随着对象的创建而被多次创建和初始化,而静态数据成员不同于非静态的数据成员,
一个类的静态数据成员仅创建和初始化一次,且在程序开始执行时创建, 然后被该类的所有对象共享。
● 下面看代码例子:
class Student
{
public:
static int getCount();
static int count;
void outPutAge(int data = age) 定义个成员函数,static数据成员可以作为默认参数
{
cout << data << endl;
}
void outPutSex(bool s = sex) 错误: 类的普通数据成员不能作为默认参数
{
}
Student myStudent1; 错误,非static数据成员不能定义为所属类的对象
static Student myStudent2; static 数据成员可以是当前类的类型
Student *myStudent3; 正确, 允许定义类的所属类型的指针类型对象
static Student &myStudent4();
private:
bool sex;
static int age;
};
int Student::age = 1; 在类外初始化私有的static数据,要添加 类名::
int Student::getCount() 在类外定义static 函数不需要添加static
{
return count; 在类的内部使用static 数据成员,不需要使用类名::
}
int main()
{
Student myStudent;
Student::count = 1; 利用作用域运算符在类外使用类名初始化公有的static数据
int temp = Student::getCount(); 调用静态成员函数
myStudent.count = 2; 使用点运算符还可以使用该类的对象初始化公有的static数据
Student::age = 2; 错误: 在类外不能初始化 私有static数据
Student *s = &myStudent; 声明一个指针指向该类型对象, 间接调用成员
s->getCount(); 通过指针调用static 成员函数
s->count; 指针调用公有的static数据成员
Student &ss = myStudent;
ss.getCount();
ss.count;
system("pause");
return 0;
}
在程序的执行过程中, 即使有多个 Student 类的对象, 也仅有一个 Student::age 的存在。
注意: static数据成员能够被类的成员函数访问,但不能在构造函数中初始化。 这是因为static数据成员在构造函数被调用之前就已经存在了。静态数据成员可以在定义时初始化,并且必须在类和所有成员函数之外。
static 成员函数
● 在static成员函数中, 不可以使用this指针, 因为static成员函数是同一个类所有对象共用的。
注意:static 成员函数仅能访问static 数据成员,不能访问非static的数据成员,也不能访问非static 的成员函数, 这是因为static成员函数没有this指针。
如果要访问非静态成员,必须通过参数传递的方式得到对象名, 在通过对象名来引用。
static成员函数在类外的调用方式如下:
类名 :: 静态成员函数名 (实参表)
或者
对象名 :: 静态成员函数名 (实参表)
注意: 对于公有的static成员函数,可以通过类名或者对象名调用; 非公有的static成员函数,只能通过对象名调用。
● 下面看代码示例:
class Time
{
public:
void print();
static void getTime()const; 错误,静态成员函数不能定义为const成员函数
static void setTime(const char *p);
static void getDate();
void setDate(int a = 9);
private:
static char szTime[60];
int date;
};
char Time::szTime[60] = "12:00:00"; 初始化static 数据成员
void Time::setTime(const char *p)
{
strcpy_s(Time::szTime, p);
}
void Time::getDate()
{
cout << date << endl; static 成员函数不能访问非静态的成员数据
setDate(5); static 成员函数也不能访问非静态的成员函数
}
void Time::setDate(int a)
{
getDate(); 但是,非静态的成员函数可以访问静态的成员函数
date = a;
}
void Time::print()
{
cout << Time::szTime << endl;
}
int main()
{
Time myTime;
myTime.print();
Time::setTime("15:00:00"); 通过类名调用static成员函数
myTime.print();
myTime.setTime("16:00:00"); 通过类对象调用static成员函数
myTime.print();
system("pause");
return 0;
}