C++指向类数据成员的指针,指向类成员函数的指针,指针或者偏移量,应用:更加统一的接口,更加隐藏的接口【C++】(ze)

指向类成员的指针

C++扩展了指针在类中的使用,使其可以指向类成员(数据成员和函数成员),这种行为是类层面的,而不是对象层面的。

C pointer 回顾

在 C 语言中,指针,既可以指向对象,也可以指向函数。给语言的便利操作带来了极大的便利

#include <iostream>
using namespace std;
void func(int a)
{
cout<<a<<endl;
}
int main()
{
int a = 100;
int *p = &a;
cout<<*p<<endl;
void (*pf)(int) = func;
pf(10);
return 0;
}

运行结果为:

在这里插入图片描述

指向类数据成员的指针

指向类数据成员的指针,是类层面的指针,而不是对象层面的指针。

语法

指向非静态数据成员的指针在定义时必须和类相关联,
在使用时必须和具体的对象相关联

由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定类的一个对象,然后,通过对象来引用指针所指向的成员。

在这里插入图片描述

应用

指向类数据成员的指针,跟普通意义上的指针用法有很大的差别。定义格式上,必须有类别限定 string Student::*pn,初始化上,也必须有类名限定&Student::name,并且定义的指针,只有通过具体的对象或对象指针才可以调用。下面进行举例说明。

我们在这里强调,是定义一个指针指向类的成员,而不是指向对象的成员。

因为类内的私有数据成员不允许外部访问,所以不允许在类外定义一个指针指向类内的私有数据成员。
下面代码中注释部分及就是举例使用类外指针指向类内的私有成员。

#include <iostream>
using namespace std;
class Student
{
public:
	Student(string n, int nu) :name(n), num(nu) {}
	string name;      //数据成员先设置为public
	int num;
};
int main()
{
	Student s("zhangsi", 100);
	Student* ps = &s;
	Student ss("wangwu", 666);
	Student* pss = &ss;
// string *tmp = &s.name;// 跟封装相违背
// cout<<*tmp<<endl;
	string Student:: * psn = &Student::name;   //定义
	//使用还需要和具体的对象产生关系
	//我们已经用过的访问方式
	//s.name;
	//ps->name;
	//换一种访问方式
	cout << s.*psn << endl;
	cout << ps->*psn << endl;

	cout << ss.*psn << endl;
	cout << pss->*psn << endl;
	return 0;
}

运行结果为:

在这里插入图片描述

但是呢,其实上面实现的意义不是很大,因为我们定义类的时候,成员变量只是私有的,上面我们把私有变量进行了释放才能实现。所以接下来我们看指向类内函数的指针。

指向类成员函数的指针

语法

定义一个指向非静态成员函数的指针必须在 三个方面与其指向的成员函数保持一致:参数列表要相同、返回类型要相同、所属的类型(类名)要相同。
由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定类的一个对象,然后,通过对象来引用指针所指向的成员。

在这里插入图片描述

#include <iostream>
using namespace std;

class Student
{
public:
	Student(string n, int nu) :name(n), num(nu) {}
	void dis(int idx)
	{
		cout <<"idx "<< idx << " name " <<name<<" num "<<num << endl;  
	}
private:
	string name;    
	int num;
};
int main()
{
	void (Student ::*pdis)(int idx) = &Student::dis;
	Student s("zhangsan", 300);
	Student ss("zhangsi", 666);
	(s.*pdis)(1);
	(ss.*pdis)(2);

	Student* ps = &s;
	Student* pss = &ss;

	(ps->*pdis)(3);
	(pss->*pdis)(4);

	return 0;
}

运行结果为:

在这里插入图片描述

指针或者偏移量

指向类成员的指针,具有指针的形而不具体指针的实质,或者,确切意义上说,不指是指针,指向类成员的指针,本质存放的不是地址,存放的偏移量。

在这里插入图片描述

指向类静态成员的指针

指向静态成员的指针的定义和使用与普通指针相同,在定义时无须和类相关联,在使用时也无须和具体的对象相关联。

语法

在这里插入图片描述

应用

也普通函数指针,唯一的区别就是,在初始化时,&A::data,要加上类名限定。

#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
class A
{
public:
static void dis();
static int data;
};
void A::dis()
{
cout<<data<<endl;
}
int A::data = 100;
int main()
{
int *pa = &A::data;
cout<<*pa<<endl;
void (*pf)() = A::dis;
pf();
return 0;
}

应用:更加统一的接口

#include <iostream>


using namespace std;

struct Point
{
    int add(int x, int y)
    {
        return x + y;
    }

    int minus(int x, int y)
    {
        return x - y;
    }

    int mul(int x, int y)
    {
        return x * y;
    }

    int div(int x,int y)
    {
        return x / y;
    }
};

int oper(Point& p, int(Point::* pf)(int x, int y), int x, int y)
{
    return (p.*pf)(x, y);
}

typedef int(Point::* PF)(int x, int y);
int main()
{
    Point p;
    PF pf = &Point::add;
    cout << oper(p, pf, 1, 2) << endl;

    pf = &Point::mul;
    cout << oper(p, pf, 1, 2) << endl;

    pf = &Point::minus;
    cout << oper(p, pf, 1, 2) << endl;

    pf = &Point::div;
    cout << oper(p, pf, 1, 2) << endl;
    
}

运行结果为:

在这里插入图片描述

应用:更加隐藏的接口

#include <iostream>

using namespace std;
class Game
{
public:
    Game()
    {
        pf[0] = &Game::f;
        pf[1] = &Game::g;
        pf[2] = &Game::h;
        pf[3] = &Game::l;
    }
    void select(int i)
    {
        if (i>= 0 && i <= 3)
        {
            (this->*pf[i])(i);
        }
    }
private:
        void f(int idx) { cout << "void f(int idx)" << idx<< endl; }
        void g(int idx) { cout << "void g(int idx)" << idx << endl; }
        void h(int idx) { cout << "void h(int idx)" << idx << endl; }
        void l(int idx) { cout << "void l(int idx)" << idx << endl; }
        enum
        {
            nc = 4
        };
        void (Game::*pf[nc])(int idx);
};

int main()
{
    Game g;
    g.select(1);
    g.select(2);
    g.select(3);
    return 0;
}

运行结果为:

在这里插入图片描述

发布了163 篇原创文章 · 获赞 94 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43648751/article/details/104664774