
- 前言
- 一、C++ this指针
- 二、静态成员变量
- 三、静态成员函数
- 四、const 成员变量、函数
- 五、友元
- 总结
前言
接着上一章继续讲一下this指针、静态成员、const成员和友元。
一、C++ this指针
this指针本质上是一个const指针,属于C++的关键字,可以默认指向当前对象,通过它可以访问当前对象的所有成员。因为this是一个指针,访问成员时需要使用 ->。我们使用this指针时需要知道以下几点知识:
- this指向当前对象,所以只有当对象创建后才能使用,所以静态成员函数不能使用
this指针 - this指针只能用于成员函数中,用在其他地方没有意义
- this是const指针,不能修改
this指针可以理解为一个属于成员函数的隐式形参,只有通过对象调用时才会为其赋值,是成员函数的一个局部变量。
class Demo{
private:
int a;
public:
void display(){
cout<<this->a<<endl;
};
};
解释一下上述原因,C++函数编译时会根据命名空间、所属类、参数列表进行重命名,这个过程叫做命名编码,成员函数最终会被编译成与对象无关的全局函数,如果函数包含成员变量,编译成员函数时会新增一个参数,把当前对象指针传递进去,这个指针就是this指针,只不过平时是隐式的,也可以显示的调用。这样就完成了成员函数和成员变量的关联,因此在成员函数执行时,实际上是通过函数寻找对象。
参考:C++ 函数编译原理和成员函数的实现
静态成员变量属于类本身,可以在多个对象之间共享,通过static关键字修饰,静态成员变量必须在类外进行初始化,因为静态成员不属于任何一个对象,所以不能通过构造函数进行初始化。调用时可以通过对象调用,也可以通过类名调用。
#include
#include
using namespace std;
class Animal{
public:
static int total;
private:
string name;
public:
Animal(string c_in):name(c_in){
total++;
}
void show(){
cout<<total<<endl;
}
};
//静态成员变量必须在类外进行初始化
int Animal::total=0;
int main(){
Animal cat("cat");
Animal dog("dog");
Animal pig("pig");
cat.show();
dog.show();
pig.show();
cout<<Animal::total<<endl;
return 0;
}
- 静态成员变量和静态变量一样,内存都位于全局内存区,只有程序结束时释放。
- 静态成员变量在类外初始化时分配内存,如果未分配程序就会报错,静态成员变量不占用对象的内存。初始化时如果未赋值,会被默认初始化为0,因为全局区变量的默认初始值为0,栈和堆的默认值不确定。
- 静态成员变量的访问也要遵循private、protected、public规则,如果上面代码total为private,
cout<就会报错。- 静态成员变量属于类,只存在一份,无论哪一个对象访问,都是访问的同一个内存,所以static会被用于单例模式。
- 常量静态成员可以在类内进行初始化,但通常也应该在类外定义该成员。
static constexpr int max=10- 静态成员变量可以用作默认实参,也可以用于不完全类型,在平时估计很少用到。
class Bar{
public:
...
private:
static Bar mem1;//正确
Bar *mem2;//正确
Bar mem3;//错误
>};
三、静态成员函数
静态成员函数不与任何对象绑定,因此,不包含this指针,也不能被声明成const函数,所以静态成员函数只能访问静态成员变量和静态成员函数,非静态成员函数(普通成员函数、常成员函数)可以访问所有成员变量。静态成员函数可以在类内、也可以在类外定义。
#include
#include
using namespace std;
class Animal{
private:
static int total;
string name;
public:
Animal(string c_in):name(c_in){
total++;
}
static void show();
};
//静态成员变量必须在类外进行初始化
int Animal::total=0;
void Animal::show(){
cout<<total<<endl;
}
int main(){
Animal cat("cat");
Animal dog("dog");
Animal pig("pig");
cat.show();
dog.show();
pig.show();
Animal::show();
return 0;
}
上面代码将show()定义为static,可以直接通过类访问。
-
const成员变量声明时只需增加const关键字,初始化时只能使用初始值列表进行初始化。
-
const成员函数声明时需要在头部结尾处加const,是
int get() const; 而不是const int get(),第一个是常成员函数,只能读取任意一个成员变量但不能修改,第二个是返回一个int常量。const成员函数在声明和定义处都需要加const。
//常成员函数和变量
#include
#include
using namespace std;
class Animal{
private:
string name;
const string skin;
public:
//skin只能通过初始值列表初始化
Animal(string name, string skin):name(name),skin(skin){}
//常成员函数只能读取属性
void show() const;
};
void Animal::show() const{
cout<<name<<"的毛色是"<<skin<<endl;
}
int main(){
Animal cat("cat","red");
cat.show();
}
const也可以声明对象,此时该对象被称为常对象,常对象只能访问常成员变量和常成员函数。
五、友元友元是一个特别有意思的东西,它是单向,也不能被传递,通过友元可以打破private、protected、public的访问限制。例如函数A是类B的友元函数,则A可以访问B的私有数据成员。友元通过friend关键字修饰。
//友元函数和友元类
#include
#include
using namespace std;
class Animal{
private:
string name;
const string skin;
public:
//skin只能通过初始值列表初始化
Animal(string name, string skin):name(name),skin(skin){}
//常成员函数只能读取属性
friend void show(Animal *animal) ;
};
//
void show(Animal *animal){
cout<<animal->name<<"的毛色是"<<animal->skin<<endl;
}
int main(){
Animal cat("cat","green");
show(&cat);//通过友元函数访问Animal类的私有成员变量
}
需要注意的因为show()是全局函数,所以不包含this指针,需要通过传入指针进行调用。一个类的成员函数也可以作为另一个类的友元函数。
//友元类
#include
#include
using namespace std;
class Country;
class Car{
private:
string name;
string skin;
public:
Car(string name, string skin):name(name),skin(skin){}
void show(Country *city);
};
class Country{
private:
string city;
public:
friend void Car::show(Country *city);
Country(string city):city(city){}
};
void Car::show(Country *city){
cout<<name<<"产自"<<city->city<<",颜色是"<<skin<<endl;
}
int main(){
Country china("China");
Car byd("byd","black");
byd.show(&china);//通过Car的show问Country类的私有成员变量
}
整个类也可以被声明为友元,此时为友元类,该类的所有成员函数都是另一个类的友元函数,只要将friend void Car::show(Country *city);换为friend class Car;不过不建议这样做。
基本上类的知识都已经讲完了把,接下来可以讲讲类的内存方面的知识。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)