C++编程入门系列之三十一(数组、指针和字符串:对象指针)

  上一讲给大家讲的是指针用作函数参数、指针型函数和函数指针的知识,今天鸡啄米把指针方面的内容结个尾,讲讲对象指针。

       一.什么是对象指针

       每个变量都占有一定的内存空间,对象同样也需要占用内存空间。对象有数据成员函数成员两种成员,但是实际上只有对象的数据成员会占用内存,函数成员则不会。我们可以通过对象名引用对象,也可以通过对象地址访问对象。对象指针就是存储对象地址的变量。声明对象指针的方式与一般的指针类似:

       类名 *对象指针名;

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

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

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

       #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;
       }

       跟一般指针一样,对象指针在使用之前也必须先赋值,因为它必须先明确指向一个对象才能正常使用,否则可能会由于被赋与了随机值而有可能访问到重要地址破坏系统数据。上面的程序运行结果是:

      17
      17

       二.this指针

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

       比如上面的CStudent类的成员函数GetAge中的语句:return m_nAge;对于编译器来说相当于执行return this->m_nAge;。为什么要有这个this指针呢?因为在执行这条语句时编译器需要知道返回的m_nAge到底属于哪一个对象,编译器事先已经把对象地址赋给this指针,调用成员函数操作数据成员时就隐含使用了这个this指针,这样就确定了访问的m_nAge属于哪个对象。

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

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

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

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

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

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

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

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

       在前面的地址相关运算中,鸡啄米讲到,用“&”运算符可以取到变量的地址,将其赋值给某个指针后就可以通过这个指针访问变量了。但是对于指向类的数据成员的指针就不同了,在类声明时并不会为类的数据成员分配内存空间,所以给指向数据成员的指针赋值只是确定了此指针指向哪个数据成员,同时也在指针中存放了该数据成员相对于类的起始地址的地址偏移量。这时通过赋值后的指针不能访问到具体的数据成员。

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

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

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

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

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

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

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

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

       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。程序的运行结果是:

       17
       17
       17

       四.指向类的静态成员的指针

       上面说了类的非静态成员的指针的概念和使用方法,对于类的静态成员,我们可以用普通指针存放它的地址,通过普通指针访问它。

       再把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;
       }

       程序运行结果是:

       student1:17
       student id=1
       student2:17
       student id=2

       这一讲的内容就这些了,根据经验,指向类的非静态成员的指针和指向类的静态成员的指针其实并不常用,大家可以重点看对象指针和this指针。如果有任何问题可以到博客留言讨论,希望我们在交流中一块提高。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值