C++中指向类成员变量指针和成员函数指针的定义方法
我们知道,如果我们需要在C++中用到关于类成员的函数或者变量,就必须使用域运算符。那么我们该如何定义指向类成员变量的指针呢?
格式为:类型名(类名::*指针名) = &类名::类的成员变量名
成员变量指针调用:对象名.*成员变量指针名
我们通过下面的简单程序来认识它:
class Myclass
{
public:
Myclass(const char* a)
{
this->str = new char[strlen(a) + 1];
strcpy(str, a);
}
char* c_str()
{
return str;
}
public:
char* str;
};
int main()
{
char* (Myclass::* ptr) = &Myclass::str;
Myclass m1("abcdef");
cout << m1.*ptr << endl;
return 0;
}
运行结果:
我们可以得出结论:m1.*ptr 等效于m1.str。
那么如何来定义指向类成员函数的指针呢?
类型名 (类名::*指针名)(参数类型表) = &类名::类的成员函数名
成员函数指针调用:(对象名.*成员函数指针名)(实参表)
class Myclass
{
public:
Myclass(const char* a)
{
this->str = new char[strlen(a) + 1];
strcpy(str, a);
}
char* c_str()
{
return str;
}
public:
char* str;
};
int main()
{
Myclass m1("abcde");
char*(Myclass::*ptr)() = &Myclass::c_str;
cout<<(m1.*ptr)();
return 0;
}
运行结果:
我们可以看出前面的调用用到非指针对象调用的 .* 和 指针对象调用使用的->*符号。那么,如何不使用这些符号而调用到那些函数呢?我们可以通过bind函数来进行绑定的操作。其中bind函数可以使用占位符和默认参数,如果需要使用占位符就需要引用命名空间std::placeholder。
int main()
{
Myclass m1("abcde");
auto fun = bind(&Myclass::c_str, &m1);
cout<<fun();
return 0;
}
nullptr的底层实现
那么能举个类成员函数指针的应用场景吗?我首先想到的就是C++2.0的nullptr了。为什么要引用nullptr呢?咱们这里简单的说一下。
C++中允许将 0 赋值给任意指针类型,但是 0 也可以赋值给普通的变量。那么,对于C++这种强类型的语言,它怎么来进行普通变量和指针之间的区分呢?
其实就是封装一个类,并生成一个object(nullptr)。这个类内部用函数模板实现了一个可以将 0 值赋值给指针类型的变量,但是不可以赋值给普通类型,作为改进的空指针版本。下面我们看具体实现:(注意:用到了上面学到的类成员变量和成员函数指针)
补充说明一点:
operator type*()函数,其实就是当改类的变量赋值给 type* 类型指针的时候就会调用到该函数。
class MyNULL
{
public:
//这个函数是允许将该类的对象赋值给普通指针
template<class T>
inline operator T*() { return 0; }
//允许将类的对象赋值给类成员变量和类成员函数类型
//其中 T 表示的是类的类型,V代表的是变脸类型(成员变量)或者返回值类型(成员函数)
template<class T, class V>
inline operator V T::*() { return 0; }
};
下面是测试代码:
int main()
{
MyNULL nullptr_m;
//定义普通指针
int* a = nullptr_m;
double* b = nullptr_m;
float* c = nullptr_m;
Myclass* d = nullptr_m;
//指向类成员函数的指针
int(Myclass::*ptr)() = nullptr_m;
//指向类成员变量的指针
int Myclass::*pointer = nullptr_m;
//定义类成员变量指针的引用
int Myclass::*&rpointer = pointer;
//error!!!!!!!!这样就可以区分普通可以赋值为 0 的类型和空指针类型都是0的情况了
int a = nullptr_m;
return 0;
}