对象指针

什么是对象指针

每个变量都占有一定的内存空间,对象同样也需要占用内存空间。对象有数据成员和函数成员两种成员,但是实际上只有对象的数据成员会占用内存,函数成员则不会。

我们可以通过对象名引用对象,也可以通过对象地址访问对象。对象指针就是存储对象地址的变量。声明对象指针的方式与一般的指针类似:

类名 *对象指针名;

使用对象名可以方便的访问对象的公有成员,同样使用对象指针也可以很容易的访问对象的公有成员。用对象指针访问对象的公有成员的形式为:

对象指针名->公有成员名;

让大家看一个简单的对象指针的例子:

#include <iostream>
using namespace std;
class CStudent
{
public:
    CStudent(int nAge=15)   { m_nAge = nAge; }       // 构造函数
    int GetAge()            { return m_nAge; }       // 内联函数,返回m_nAge
private:
    int m_nAge;        // 私有数据
};
int main()
{
    CStudent student(17);      // 声明对象student并对其初始化
    CStudent *ptr;             // 声明对象指针
    ptr = &student;            // 初始化对象指针
    cout << student.GetAge() << endl;   // 通过对象名访问对象的成员
    cout << ptr->GetAge() << endl;      // 通过对象指针访问对象的成员
    return 0;
}

在这里插入图片描述
跟一般指针一样,对象指针在使用之前也必须先赋值,因为它必须先明确指向一个对象才能正常使用,否则可能会由于被赋与了随机值而有可能访问到重要地址破坏系统数据。

this指针

this指针实际上就隐含于类的成员函数中,它指向成员函数正在操作的对象。构造函数和析构函数也不例外,也同样隐含了this指针。它也是一个指针,只是有点特殊。

比如上面的CStudent类的成员函数GetAge中的语句:return m_nAge;对于编译器来说相当于执行return this->m_nAge;

为什么要有这个this指针呢?

因为在执行这条语句时编译器需要知道返回的m_nAge到底属于哪一个对象,编译器事先已经把对象地址赋给this指针,调用成员函数操作数据成员时就隐含使用了这个this指针,这样就确定了访问的m_nAge属于哪个对象。

一般在软件开发中不会直接用到this指针访问数据成员,有时需要将此对象作为参数传递给某个函数时会使用this指针,亦或是写程序时忘记某个函数名,输入this->后vs2010会提示出所有成员函数。

指向类的非静态成员的指针

类的成员都是变量、对象、函数等,我们同样可以定义存放它们的地址的指针,从而使指针指向对象的成员,通过指针就可以访问对象的成员了。但是通过这种指向成员的指针一样也只能访问公有成员。

声明指向非静态成员的指针的语法形式为:

类型说明符 类名::*指针名;       // 声明指向公有数据成员的指针
类型说明符 (类名::*指针名)(形参表);  // 声明指向公有成员函数的指针

指向成员的指针也要先声明再赋值,然后才能引用。给指向成员的指针赋值就是要说明此指针指向类的哪一个成员。

为指向数据成员的指针赋值的语法形式为:

指针名 = &类名::数据成员名;

在前面的地址相关运算中,讲到,用“&”运算符可以取到变量的地址,将其赋值给某个指针后就可以通过这个指针访问变量了。

但是对于指向类的数据成员的指针就不同了,在类声明时并不会为类的数据成员分配内存空间,所以给指向数据成员的指针赋值只是确定了此指针指向哪个数据成员,同时也在指针中存放了该数据成员相对于类的起始地址的地址偏移量。这时通过赋值后的指针不能访问到具体的数据成员。

在声明了类的对象后就会为对象分配内存,这样根据对象的起始地址和指向数据成员的指针中存放的偏移量就可以访问到对象的数据成员了。

通过对象和指向数据成员的指针访问公有数据成员的语法形式为:

对象名.*指向数据成员的指针名
或者 对象指针名->*指向数据成员的指针名

为指向成员函数的指针赋值的语法形式为:

指针名 = &类名::函数成员名;

在上面的形式为成员函数指针赋值以后还不能直接用此指针调用成员函数,必须先声明了类的对象,再通过对象和指向非静态成员函数的指针调用成员函数。

调用的语法形式为:

(对象名.*指向成员函数的指针名)(形参表)
或者 (对象指针名->*指向成员函数的指针名)(形参表)

在为成员函数指针赋值时,还有用对象和成员函数指针调用成员函数时,我们都要注意成员函数指针的返回值类型和形参表一定要和指向的成员函数一致。

再以上面对象指针中的例子为基础修改下,让大家看看访问对象公有成员函数的几种方式:

#include <iostream>
using namespace std;
class CStudent
{
public:
    CStudent(int nAge=15)   { m_nAge = nAge; }       // 构造函数
    int GetAge()            { return m_nAge; }       // 内联函数,返回m_nAge
private:
    int m_nAge;        // 私有数据
};
int main()
{
    CStudent student(17);      // 声明对象student并对其初始化
    CStudent *ptr;             // 声明对象指针
    int (CStudent::*pGetAge)();// 声明指向成员函数GetAge的指针
    
    pGetAge = &CStudent::GetAge;// 为pGetAge赋值
    ptr = &student;             // 初始化对象指针
    cout << student.GetAge() << endl;   // 通过对象名访问成员函数
    cout << ptr->GetAge() << endl;      // 通过对象指针访问对象的成员函数
    cout << (student.*pGetAge)() << endl; // 通过成员函数指针访问成员函数
    return 0;
}

上面的例子中,先声明了一个CStudent类的对象student并初始化,又分别声明了一个指向对象student的指针ptr和指向成员函数GetAge的指针并各自初始化后,分别通过对象名、对象指针和指向成员函数的指针这三种方式访问公有成员函数GetAge。
在这里插入图片描述

指向类的静态成员的指针

对于类的静态成员,我们可以用普通指针存放它的地址,通过普通指针访问它。

再把CStudent类的例子修改下,说明怎样通过指向类的静态数据成员的指针访问静态数据成员:

#include <iostream>
using namespace std;
class CStudent
{
public:
    CStudent(int nAge=15)   { m_nAge = nAge; m_nCount++; }       // 构造函数
    CStudent(CStudent &stu);                         // 拷贝构造函数
    int GetAge()            { return m_nAge; }       // 内联函数,返回m_nAge
    static int m_nCount;   // 静态数据成员声明
private:
    int m_nAge;          // 私有数据
};
CStudent::CStudent(CStudent &stu)
{
    m_nAge = stu.m_nAge;
    m_nCount++;
}
int CStudent::m_nCount = 0;   // 静态数据成员初始化
int main()
{
    int *pCount = &CStudent::m_nCount;  // 声明一个int型的指针,指向静态数据成员m_nCount
    CStudent student1(17);              // 声明对象student1并对其初始化
    cout << "student1:" << student1.GetAge() << endl;
    cout << "student id=" << *pCount << endl;      // 通过指针访问静态数据成员
    CStudent student2(student1);                   // 声明对象student2并用student1初始化它
    cout << "student2:" << student2.GetAge() << endl;
    cout << "student id=" << *pCount << endl;      // 通过指针访问静态数据成员
    return 0;
}

在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
指向类的成员的指针 在C++中,可以说明指向类的数据成员和成员函数的指针。 指向数据成员的指针格式如下: ::* 指向成员函数的指针格式如下: (::*)() 例如,设有如下一个类A: class A { public: int fun (int b) { return a*c+b; } A(int i) { a=i; } int c; private: int a; }; 定义一个指向类A的数据成员c的指针pc,其格式如下: int A:: *pc = &A::c; 再定义一个指向类A的成员函数fun的指针pfun,其格式如下: int (A:: *pfun)(int) = A::fun; 由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定A类的一个对象,然后,通过对象来引用指针所指向的成员。例如,给pc指针所指向的数据成员c赋值8,可以表示如下: A a; a.*pc = 8; 其中,运算符.*是用来对指向类成员的指针来操作该类的对象的。 如果使用指向对象指针来对指向类成员的指针进行操作时,使用运算符->*。例如: A *p = &a; //a是类A的一个对象,p是指向对象a的指针。 p ->* pc = 8; 让我们再看看指向一般函数的指针的定义格式: *() 关于给指向函数的指针赋值的格式如下: = 关于在程序中,使用指向函数的指针调用函数的格式如下: (*)() 如果是指向类的成员函数的指针还应加上相应的对象名和对象成员运算符。 下面给出一个使用指向类成员指针的例子: #include class A { public: A(int i) { a=i; } int fun(int b) { return a*c+b; } int c; private: int a; }; void main() { A x(8); //定义类A的一个对象x int A::*pc; //定义一个指向类数据成员的指针pc pc=&A::c; //给指针pc赋值 x.*pc=3; //用指针方式给类成员c赋值为3 int (A::*pfun)(int); //定义一个指向类成员函数的指针pfun pfun=A::fun; //给指针pfun赋值 A *p=&x; //定义一个对象指针p,并赋初值为x cout<*pfun)(5)<<endl; //用对象指针调用指向类成员函数指针pfun指向的函数 } 以上程序定义了好几个指针,虽然它们都是指针,但是所指向的对象是不同的。p是指向类的对象;pc是指向类的数据成员;pfun是指向类的成员函数。因此它们的值也是不相同的。 对象指针对象引用作函数的参数 1. 对象指针作函数的参数 使用对象指针作为函数参数要经使用对象作函数参数更普遍一些。因为使用对象指针作函数参数有如下两点好处: (1) 实现传址调用。可在被调用函数中改变调用函数的参数对象的值,实现函数之间的信息传递。 (2) 使用对象指针实参仅将对象的地址值传给形参,而不进行副本的拷贝,这样可以提高运行效率,减少时空开销。 当形参是指向对象指针时,调用函数的对应实参应该是某个对象的地址值,一般使用&后加对象名。下面举一例子说明对象指针作函数参数。 #include class M { public: M() { x=y=0; } M(int i, int j) { x=i; y=j; } void copy(M *m); void setxy(int i, int j) { x=i; y=j; } void print() {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值