-
2020-09-19 21:05:41
一、对象指针:
作用:指向对象的指针。用来容纳对象地址的指针,指向的是一个对象。
定义:类名 *对象指针名;eg:Time *ptr;
Time *ptr;//定义对象指针 Time t1; //定义对象t1; ptr=&t1; //将对象t1的地址赋给对象指针;
使用方式:
*ptr 表示ptr指向的对象t1;
(*ptr).hour 表示ptr指向的对象中hour的成员;
ptr->hour 表示ptr指向的对象中hour的成员;
ptr->get() 表示ptr指向的对象中get()成员函数;
二、指向对象成员的指针:
对象成员有两类,一是数据成员,二是函数成员。因此指向对象的成员的指针也分为两种,一是普通的指向数据的指针,二是指向函数的指针。
- 指向数据成员的指针,即数据指针。
int *p; //定义指向整形数据的指针; p=&t.hour; //将对象的某个数据成员的地址赋给p,p指向t.hour;
- 指向函数成员的指针,即函数指针。
函数指针的定义: 函数返回值类型 (*指针变量名)(函数参数表列)例如:void(*p)();
void(*p)();//函数指针的定义原则: 函数返回值类型 (*指针变量名)(函数参数表列)
为了确保函数指针与指向的函数相匹配,必须实现函数返回值、函数参数表列相匹配。在指向成员函数的指针中,除了上述两点外,还必须满足所属类的匹配。
因此,指向对象成员函数的指针定义及使用原则如下:
数据类型名 (类名::*指针变量名)(参数表列);
void(Time::*p)();//定义指向Time类中成员函数的指针
使指针变量指向一个类中成员函数的一般形式:
指针变量名=&类名::成员函数名 ;
p=&Time::get;//将time类中成员函数get的地址赋给函数指针p;
更多相关内容 - 指向数据成员的指针,即数据指针。
-
C++类和对象的使用之对象指针
2019-07-04 21:38:07对象指针遵循一般变量指针的各种规则:类名 *对象指针名; 对象指针名*成员名; 对象指针在使用之前,也一定要先进行初始化,让它指向一个已经声明过的对象,然后再使用。通过对象指针,可以访问到所指向对象的公有...类和对象的使用之对象指针
对象指针的一般概念
对象指针:指向类的成员的指针。在C++中,可以说明指向类的数据成员和成员函数的指针。
对象指针遵循一般变量指针的各种规则:类名 *对象指针名;
对象指针名*成员名;
对象指针在使用之前,也一定要先进行初始化,让它指向一个已经声明过的对象,然后再使用。通过对象指针,可以访问到所指向对象的公有成员。指向对像的指针
在建立对像时,编译系统会为每一个对像分配一定的存储空间,以存放其成员,对像空间的起始地址就是
对像的指针。可以定义一个指针变量,用来存和对像的指针。如果有一个类:class Time { public: int hour; int minute; int sec; void get_time(); }; void Time::get_time() { cout << hour << ":" << minute << ":" << sec << endl; }
在此有以下语句:
Time *pt;//定义pt 为指向Time类对像的指针变量 Time t1;//定义t1为Time类对像 pt=&t1;//将t1的起始地址赋给pt
这样,pt 就是指向Time类对象的指针变量,它指向对象t1。
定义指向类对象的指针变量的一般形式为:类名 *对象指针名;
可以通过对象指针访问对象和对象的成员。如:
*pt pt所指向的对像,即t1 (*pt).hour pt所指向的对象中的hour成员,即t1.hour pt->get_time() pt把指向的对象中的get_time函数,即t1.get_time() (*pt).get_time()
指向对象成员的指针
a.指向对象数据成员的指针
定义指向对象数据成员的指针的方法与定主指向变通的指针变量的方法相同。如:
int *p;
定义指向对象数据成员的指针变量的一般形式为:
数据类型名 *指针变量名;
b.指向对象成员函数的指针
定义指向对象成员函数的指针变量的方法和定义指向变通函数的指针变量方法有所不同。
定义指向变通函数的指针变量的方法:数据类型名 (*指针变量名)();如: void (*p)();//p是指向void型函的指针变量
定义指向成员函的指针:
数据类型名 (类名::*指针变量名)(); 使指针变量指向一个公用成员函数的一般形式为 指针变量名=&类名::成员函数名;
示例:
1 #include <iostream> 2 using namespace std; 3 class Time 4 { 5 public: 6 Time(int ,int ,int ); 7 int hour; 8 int minute; 9 int sec; 10 void get_time(); 11 }; 12 Time::Time(int h,int m,int s) 13 { 14 hour = h; 15 minute= m; 16 sec = s; 17 } 18 void Time::get_time() 19 { 20 cout << hour << ":" << minute << ":" << sec << endl; 21 } 22 23 int main() 24 { 25 Time t1(10,13,56); //定义Time类对象t1 26 int *p1=&t1.hour;//定义指向整型数据的指针变量p1,并使p1指向t1.hour 27 cout << *p1 << endl; 28 t1.get_time();//调用对象t1的成员函数get_time() 29 30 Time *p2=&t1;//定义指向Time类对象的指针变量p2,并使p2指向t1 31 p2->get_time();//调用p2所指向对象的get_time()函数 32 void (Time::*p3)();//定义指向Time类公用成员函数get_time 33 p3 = &Time::get_time;//使p3指向Time类公用成员函数get_time 34 (t1.*p3)();//调用对象t1中p3所指的成员函数 35 36 return 0; 37 }
4、指向类的非静态成员的指针(非指向对象,而是指向对象成员)
指向对象成员的指针使用前也要先声明,再赋值,然后引用,因此首先要声明指向该对象所在类的成员的指针。注意,通过指向成员的指针也只能访问到公有成员。
语法形式:类型说明符 类名::*指针名; //声明指向公有数据成员的指针 类型说明符 (类名::*指针名)(参数表);//声明指向公有函数成员的指针
对数据成员指针赋值:
指针名 = &类名::数据成员;
此时还不能通过指针访问变量。类的声明只确定了各个数据成员的类型、所占内存大小以及它们的相对位置,在声明时并不为数据成员分配具体的地址。因此经上述赋值之后,只是说明了被赋值的成员指针式专门用于指向哪个数据成员的,同时在指针中存放该数据成员在类中的相对位置,当然通过这样的指针现在并不能访问什么。
由于类是通过对象而实例化的,在声明类的对象时才会为具体的对象分配内存空间,这时只要将对象在内存中的起始地址与成员指针中存放的相对偏移结合起来就可以访问到对象的数据成员了。语法形式:对象名.*类成员指针名 或 对象指针名à*类成员指针名 成员函数指针赋值: 指针名 = 类名::函数成员名; 经过上述对成员函数指针赋值之后,还不能用指针直接调用成员函数,而是需要首先声明类的对象,因为必须要通过对象来调用非静态成员函数。 利用指针调用成员函数: (对象名.*类成员指针名)(参数表) 或 (对象指针名à*类成员指针名)(参数表)
5、指向类的静态成员的指针
类的静态成员可以用普通的指针来指向和访问。/**形式上把静态成员看成普通变量就可以**/
对象指针:在C++中,可以说明指向类的数据成员和成员函数的指针。
1. 对象指针作函数的参数
使用对象指针作为函数参数要经使用对象作函数参数更普遍一些。因为使用对象指针作函数参数有如下两点好处:
-
实现传址调用。可在被调用函数中改变调用函数的参数对象的值,实现函数之间的信息传递。
-
使用对象指针实参仅将对象的地址值传给形参,而不进行副本的拷贝,这样可以提高运行效率,减少时空开销。
当形参是指向对象指针时,调用函数的对应实参应该是某个对象的地址值,一般使用&后加对象名。 下面举一例子说明对象指针作函数参数。
1 #include <iostream.h> 2 class M 3 { 4 public: 5 M() { x=y=0; } 6 M(int i, int j) { x=i; y=j; } 7 void copy(M *m); 8 void setxy(int i, int j) { x=i; y=j; } 9 void print() { cout<<x<<","<<y<<endl; } 10 private: 11 int x, y; 12 }; 13 14 void M::copy(M *m) 15 { 16 x=m->x; 17 y=m->y; 18 } 19 20 void fun(M m1, M *m2); 21 void main() 22 { 23 M p(5, 7), q; 24 q.copy(&p); 25 fun(p, &q); 26 p.print(); 27 q.print(); 28 } 29 30 void fun(M m1, M *m2) 31 { 32 m1.setxy(12, 15); 33 m2->setxy(22,25); 34 } 35 36 输出结果为: 37 5,7 38 22,25
从输出结果可以看出,当在被调用函数fun中,改变了对象的数据成员值[m1.setxy(12, 15)]和指向对象指针的数据成员值[m2->setxy(22, 25)]以后,可以看到只有指向对象指针作参数所指向的对象被改变了,而另一个对象作参数,形参对象值改变了,可实参对象值并没有改变。因此输出上述结果。
2. 对象引用作函数参数
在实际中,使用对象引用作函数参数要比使用对象指针作函数更普遍,这是因为使用对象引用作函数参数具有用对象指针作函数参数的优点,而用对象引用作函数参数将更简单,更直接。所以,在C++编程中,人们喜欢用对象引用作函数参数。现举一例子说明对象引用作函数参数的格式。
1 #include <iostream.h> 2 class M 3 { 4 public: 5 M() { x=y=0; } 6 M(int i, int j) { x=i; y=j; } 7 void copy(M &m); 8 void setxy(int i, int j) { x=i; y=j; } 9 void print() {cout<<x<<","<<y<<endl; } 10 private: 11 int x, y; 12 }; 13 14 void M::copy(M &m) 15 { 16 x=m.x; 17 x=m.y; 18 } 19 20 void fun(M m1, M &m2); 21 22 void main() 23 { 24 M p(5, 7), q; 25 q.copy(p); 26 fun(p, q); 27 p.print(); 28 q.print(); 29 } 30 31 void fun(M m1, M &m2) 32 { 33 m1.setxy(12, 15); 34 m2.setxy(22, 25); 35 }
该例子与上面的例子输出相同的结果,只是调用时的参数不一样。
3.this指针
this指针是一个隐含于每一个类的成员函数中的特殊指针,它用于指向正在被成员函数操作的对象。实际过程是,当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。/难怪:在成员函数之外无法访问数据成员,找不到对象呀!(当然中间的private,protected另作谈论/
当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含作用this指针。而通常不去显式地使用this指针来引用数据成员。同样也可以使用*this来标识调用该成员函数的对象。下面举一例子说明this指针的应用。
1 #include <iostream.h> 2 class A 3 { 4 public: 5 A() { a=b=0; } 6 A(int i, int j) { a=i; b=j; } 7 void copy(A &aa); //对象引用作函数参数 8 void print() {cout<<a<<","<<b<<endl; } 9 private: 10 int a, b; 11 }; 12 13 void A::copy(A &aa) 14 { 15 if (this == &aa) return; //这个this是操作该成员函数的对象的地址,在这里是对象a1的地址 16 *this = aa; //*this是操作该成员函数的对象,在这里是对象a1。 17 //此语句是对象aa赋给a1,也就是aa具有的数据成员的值赋给a1的数据成员 18 } 19 20 void main() 21 { 22 A a1, a2(3, 4); 23 a1.copy(a2); 24 a1.print(); 25 }
-
-
Java中的对象类型的引用到底是不是指针
2016-10-21 11:04:23先放结论:可以认为Java中的引用就是指针,是一种限制的指针,不能参与整数运行和指向任意位置的内存,并且不用显示回收对象。 作为一名程序员,我们应该对新知识和新技术刨根问底,而不应泛泛而谈。我未曾接触到...初学Java,感觉引用和c中的指针很像,特此学习,mark一下
原文详见:http://blog.csdn.net/linyt/article/details/1573864
先放结论:可以认为Java中的引用就是指针,是一种限制的指针,不能参与整数运行和指向任意位置的内存,并且不用显示回收对象。
作为一名程序员,我们应该对新知识和新技术刨根问底,而不应泛泛而谈。我未曾接触到Java的时候,我想听得最多的东西还是关于Java中不存在指针的问题。此时,我会不断地想:如果Java不存在指针的话,那么是如何实现复杂的数据结构?这样的语言与VB有什么差别?如果一个静态过程式或面向对象语言,如果不存在指针的话,那它如何会得到程序员的喜爱呢?功能是何其的有限?幸好有机会和一位师弟在交流C#,当时我也没有接触过C#,不过从他的观点令我看清楚了一些问题。我还是很清楚地记得他说了一句:C#中同样有指针,不过是有限制的指针,因此在C#中把它称为引用(references)。经过对Java的学习后,我非常赞同他的那句话。即是Java中也存在指针,不过是限制的指针,因此在Java语言的规范说明里把它称为引用。下在从C++中的对象类型为依据,谈谈Java语言中的引用到底与C++中的哪种对象类型更类似。
Java的对象类型
在这里,我不泛谈程序语言原理方面的知识,如何为引用,何为指针。只以C++的对象类型为蓝本,讨论C++中对象类型与Java对象类型的异同。
C++的对象类型分为三种:对象变量,对象指针和对象引用(这里特指是C++的引用)。对象变量,与基本数据类型变量一样,分配在栈中,对象在栈的生命空间结束后,系统会自动释放对象所占用的空间;对象指针,与C语言中的指针一样,都是一个地址,它指向栈中或堆中的一个对象。对象引用是C++中与C不同之外,形象地说,引用就是一个别名,定义引用的时候必须一起初始化,不能引用不存在的对象。下面是C++中定义三种对象类型的代码:
String a(“string a”);
String *pA = &a;
String *pB = new String(“string b”);
String &c = a;
语句1中定义一个String变量a,它的内容是”string a”;语句2中定义一个String对象指针,它指向对象a(栈对象);语句3中定义一个String对象指针,不过它指向一个分配在堆中的对象。最后一个语句是定义一个String对象的引用c,它引用a,也即是说c是a的别名,即同一个变量,两个不同的名字而已。只要改变a或c,该变量内容都会发生改变的。
Java中的对象类型只有一种,那就是引用(注意是Java的引用,而非C++的引用)。下面是定义一个引用的代码。
String s = new String(“string”);
在执行此代码时,在内存空间生成的结构如下面所示:
+--------+ +-------------------------+
|引用s |--------------------à|对象内容为“string”|
+-------- + +-------------------------+
上面的语句中其实做了两件事情,在堆中创建了一个String对象,内容为”string”,在栈中创建了一个引用s,它指向堆中刚创建好的String对象。并且引用s值的改变不影响它所指的对象,只有通过它调用对象的方法对可能改变对象的内容。请看如下语句:
s = new String(“abc”);
在上面这个语句中,只改变s的值,因此不会对内容为”string”对象造成影响(不考虑垃圾回收情况)。只不过是s指向堆中的新对象而已,从指针上来说,就是s的值改变了而已。
从上面来看,Java的引用,并不与C++的引用相同,因此它不是一个别名;与对象变量也不同,它只是表示一个内存位置,该位置就是存在一个对象的位置,而不是真实的对象变量。并且从指针的意义角度来说,C/C++的指针与Java的引用却是不谋而合。它们都表是一个内存地址,都可以通过这个内存地址来操纵它所对应的对象。因此Java的引用更像C++中的指针,在下文中把它称为Java中的指针,同样也可称为Java中的引用。
Java中的指针与C++中的指针
本文开始提到Java中的指针是限制的指针,那么在这里分析Java中的指针可以执行什么运算符。
在C++的对象指针里面,出现的指针运算符主要有以下几个:*,->。
运算符*是返回指针所指向的对象,而->是返回指针所指向对象的数据成员或方法成员。由于不存在对象变量,而是通过指针来访问对象的,因此Java中不需要提供*运算符,这是Java优化了C++的一个指针问题。对于->运行符,Java的指针是提供的,不过是采用.运算符的方式提供,看起来与C++中对象变量的.运算符一样,其实意义是有不一样的地方。
如String s = new String(“abc”);
s.indexOf(“a”);
与下面C++代码等价的
String *s = new String(“abc”);
s->indexOf(“a”);
对于C++中对象变量出现的复制构造函数,“=”运算符以及“==”运算符问题同样在Java中出现。
在C++中,如果类没有定义它的“=”运算符,那么有可能会出现浅度复制,而非深度复制,Java也有类似的问题。两者要程序员采用深度复制的策略编写构造函数;如果C++中的对象没有定义“==”运算法,那么它会依次对两个变量比较它的数据成员,看是否都相等。如果定义则按用户的比较方式进行比较。在Java,Object对象定义了equals方法,这个方法是用来比较两个对象如果相等的,Object中的equals方法只是比较两个指针的值是否相等而已,要根据所指向的对象内容进行比较,那应重写该类的equals方法。
正因为Java中存在指针,所以使用Java同样能写出丰富的数据结构,java中的集合框架就是最好的例子。
上面只要谈到Java中指针与C++中指针相同或类似的部分,我觉得两者之间是有差别的,差别主要有三个。
C++中的指针是可以参与和整数的加减运算的,当一个指对指向一个对象数组时,可以通过自增操作符访问该数组的所有元素;并且两个指针能进行减运算,表示两个指表所指向内存的“距离”。而Java的指针是不能参与整数运算和减法运算的。
C++中的指针是通过new运算或对象变量取地址再进行赋值而初始化的,可以指向堆中或栈中的内存空间。Java同样是类似的,通new运算得到初始化。Java中指针只能是指向堆中的对象,对象只能生存在堆中。C语言是可以通过远指针来指向任意内存的地址,因而可以该问任意内存地址(可能会造成非法访存);Java中的指针向的内存是由JVM来分配的中,由于new运算来实现,不能随所欲为地指向任意内存。
C++中通过delete和delete[] 运算符进行释放堆中创建的对象。如果对象生存周期完结束,但没有进行内存释放,会出现内存泄露现象。在Java中,程序员不用显式地释放对象,垃圾回收器会管理对象的释放问题,不用程序员担心。Java使用了垃圾回收机制使得程序不用再管理复杂的内存机制,使软件出现内存泄露的情况减少到最低。即Java的引用不用关心内存回收的问题。
小结
通过上面的分析,我们可以得到这样的结论:Java中的引用与C++中的引用是不同的,并且Java中的引用更像C++中的指针。因此,可以认为Java中的引用就是指针,是一种限制的指针,不能参与整数运行和指向任意位置的内存,并且不用显示回收对象。除了Java外,就本文开头提到的C#以及VB.NET中出现的引用,都类似于C++中的指针。Java中的采用引用的说法,其实是想程序员忘记指针所带来的痛苦;Java的引用比C++中的指针好用得多了,也容易管理,同时提供内存管理机制,让大家用得安心,写得放心而已。 -
【C++】 指向类的指针 指向类的对象 对象指针 函数指针 引用
2020-08-26 10:47:21文章目录C++类的对象和类的指针的区别指向地址的指针指针本身的大小指向数组的指针指针数组指向指针数组的指针多维指针数组函数参数中使用指针数组指针传址实现数组求和函数指针模仿C++ 类别函数指针数组对象指针...文章目录
一个指向 C++ 类的指针与指向结构的指针类似,
访问指向类的指针的成员,需要使用成员访问运算符 ->,就像访问指向结构的指针一样。
与所有的指针一样,您必须在使用指针之前,对指针进行初始化。C++的精髓之一就是多态性,只有指针或者引用可以达到多态。对象不行
用指针:
第一实现多态。
第二在函数调用,传指针参数。不管你的对象或结构参数多么庞大,你用指针,传过去的就是4个字节。如果用对象,参数传递占用的资源就太大了类的指针:他是一个内存地址值,他指向内存中存放的类对象(包括一些成员变量所赋的值).
对象:他是利用类的构造函数在内存中分配一块内存(包括一些成员变量所赋的值).
在应用时:
1.引用成员: 对象用" . "
操作符; 指针用" -> "
操作符.
2.生命期: 若是成员变量,则是类的析构函数来释放空间;若是函数中的临时变量,则作用域是该函数体内;而指针,则需利用delete 在相应的地方释放分配的内存块.
注意:用new
,一定要delete
…类的对象:用的是内存栈,是个局部的临时变量.
类的指针:用的是内存堆,是个永久变量,除非你释放它.C++类的对象和类的指针的区别
#include <iostream> #include <string> using namespace std; class Student { public: static int number; string name; public: Student() { } void set(string str) { name = str; number++; // 调用静态数据成员 } void print() // 态成员函数 print() { std::cout < < name < <" : The number of the students is " < < number < < " numbers." < < std::endl; // 调用静态数据成员 } }; int Student::number = 0; // 静态数据成员初始化 int main(int argc, char** argv) { Student* s1; s1 = new Student(); s1->set("111"); Student s2; s2.set("222"); s1->print(); s2.print(); return 0; }
对于类student ,定义了一个对象和一个指针。
类的指针:是内存地址值,指向内存中存放的类对象
对象:利用类的构造函数在内存中分配一块内存
在应用时:
1.引用成员: 对象用" . “操作符; 指针用” -> "操作符.
2.生命期: 若是成员变量,则是类的析构函数来释放空间;若是函数中的临时变量,则作用域是该函数体内;而指针,则需利用delete 在相应的地方释放分配的内存块.
注意:用new ,一定要delete…类的对象:用的是内存栈,是个局部的临时变量.
类的指针:用的是内存堆,是个永久变量,除非你释放它.堆栈中到底存储数据包括:函数的参数,函数的局部变量等,这些数据是按照一定的顺序组织在一起的,我们称之为一个堆栈帧(Stack Frame)。一个堆栈帧对应一次函数的调用。在函数开始时,对应的堆栈帧已经完整地建立了(所有的局部变量在函数帧建立时就已经分配好空间了,而不是随着函数的执行而不断创建和销毁的);在函数退出时,整个函数帧将被销毁。
在文中,我们把函数的调用者称为Caller(调用者),被调用的函数称为Callee(被调用者)。之所以引入这个概念,是因为一个函数帧的建立和清理,有些工作是由Caller完成的,有些则是由Callee完成的。
堆栈是用来支持函数的调用和执行的
当类是有虚函数的基类,Func是它的一个虚函数,则调用Func时:
类的对象:调用的是它自己的Func;
类的指针:调用的是分配给它空间时那种类的Func;对于一个类的对象和这个类的指针(用new运算符分配内存)在应用时有何区别
1.类和对象是两回事,对象是类的实例;
2.对象是在栈中分配的,使用new生成的对象是在堆中分配的;
3.要发挥虚函数的强大作用,必须使用指针来访问对象.指针可以实现多态,直接用对象不行
执行定义对象,在栈空间
new处的在堆注意名字的类型.
一个是Student
一个是Student*
Student是直接访问一个对象
Student*是间接访问一个对象,因为通过了一个指针作媒介.
类型决定了你能做什么.其实作用基本一样 都是为了调用类的成员变量 和成员函数用的
当你希望明确使用这个类的时候,最好使用对象,如果你希望使用C++中的动态绑定,则最好使用指针或者引用
指针和引用用起来更灵活,容易实现多态等类的指针:他是一个内存地址值,他指向内存中存放的类对象(包括一些成员变量所赋的值).
对象,他是利用类的构造函数在内存中分配一块内存(包括一些成员变量所赋的值).1.在类的声明尚未完成的情况下,可以声明指向该类的指针,但是不可声明该类的对象…
2.父类的指针可以指向子类的对象…定义对象实例时,分配了内存。指针变量则未分配类对象所需内存
指针变量是间接访问,但可实现多态(通过父类指针可调用子类对象),并且没有调用构造函数。
直接声明可直接访问,但不能实现多态,声明即调用了构造函数(已分配了内存)。
至于那个效率高要看程序调用过程而定。C++的精髓之一就是多态性,只有指针或者引用可以达到多态。对象不行
用指针:
第一实现多态。
第二,在函数调用,传指针参数。不管你的对象或结构参数多么庞大,你用指针,传过去的就是4个字节。如果用对象,参数传递占用的资源就太大了没有例子不说话
指向地址的指针
指针本身的大小
指向数组的指针
指针数组
指向指针数组的指针
多维指针数组
函数参数中使用指针
#include <stdio.h> int myswap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; } int main() { int x = 50; int y = 30; myswap(&x, &y); printf("x:%d y:%d\n", x, y); return 0; } // x:30 y:50 // 这个程序看似简单, 但是却应用到了而很多高级的算法, // 指针 引用 当初不理解,现在终于理解了!
数组指针传址实现数组求和
#include <iostream> using namespace std; int mysum(int length, int *data){ int myresult = 0; int i; for(i = 0; i < length; i++) { myresult += *(data + i); cout << *(data + i) << endl; cout << data + i << endl; } return myresult; } int main() { int x[5] = {1, 2, 3, 4, 5}; int restult; restult = mysum(5, x); cout << x << endl; printf("%d\n", restult); return 0; } // 输出结果: //0x7ffecd866750 //1 //0x7ffecd866754 //2 //0x7ffecd866758 //3 //0x7ffecd86675c //4 //0x7ffecd866760 //5 //0x7ffecd866750 //15
函数指针
#include <iostream> using namespace std; int add(int a, int b); int main(int argc, char **argv) { int (*myfunc)(int a, int b); myfunc = add; int x = myfunc(12, 36); cout << x << endl; return 0; } int add(int a, int b) { return a + b; } // 48
模仿C++ 类别
#include <iostream> using namespace std; struct mynum{ int a; int b; int result; void(*mod_add)(int a, int b, int *result); }; void madd(int a, int b, int *result){ (*result)=(a + b) % 13; } int main(void){ struct mynum mnum; mnum.a = 12; mnum.b = 26; mnum.mod_add=madd; mnum.mod_add(mnum.a, mnum.b, &mnum.result); cout << mnum.result << endl; return 0; } // 12
函数指针数组
#include <stdio.h> #include <stdlib.h> int add(int a, int b){ return a + b; } int sub(int a, int b){ return a - b; } int main (int argc, char **argv) { int (*operate_func[])(int, int) ={add, sub}; int myresult = 0; int oper = atoi(*++argv); printf("%d\n", oper); int mynum; while (*++argv != NULL) { mynum = atoi(*argv); printf("%d ", mynum); myresult = operate_func[oper](myresult, mynum); } printf("\n%d\n", myresult); return 0; } // ./test 0 1 13 52 // 0 ->参数含义是调用add函数,实际上是按照下标进行访问, // 如果是 1 就调用sub函数。 // 1 13 52 -> 依次读取数据进行累加。 // 66 -> 最终累加和。
对象指针
C++ 中经常出现使用对象指针,而不是直接使用对象本身的代码,
Object *myObject = new Object;
而不是使用:
Object myObject;
要不就是调用对象的方法
myObject.testFunc();
而是得写成这样:
myObject->testFunc();
何时使用动态分配(使用 new 方法)
什么时候该使用指针?定义对象的方式比起使用手工动态分配(或new指针)的方式会更加合理以及安全。
通过 Object myObject 方式定义对象,对象的生存期是在其作用域内自维护(automatic storage),这个意味着程序离开对象的作用域之后,对象将被自动销毁。
当通过 new Object() 方式分配对象时,对象的生存期是动态的,这个意味着若不显式地 detete 对象,对象将一直存在。你应该只在必要的时候使用动态分配对象。换句话说,只要有可能,你应该首选定义可自维护的对象。这里是两个常见需要动态分配对象的情况:
分配不限制作用域的对象,对象存储在其特定的内存中,而不是在内存中存储对象的拷贝。如果对象是可以拷贝/移动的,一般情况下你应该选择使用定义对象的方式。
定义的对象会消耗大量内存,这时可能会耗尽栈空间。如果我们永远不需要考虑这个问题那该多好(实际大部分情况下,我们真不需要考虑),因为这个本身已经超出 C++ 语言的范畴,但不幸的是,在我们实际的开发过程中却不得不去处理这个问题。
当你确实需要动态分配对象时,应该将对象封装在一个智能指针(smart pointer)或其他提供RAII机制的类型中(类似标准的 container)。智能指针提供动态对象的所有权语义(ownership)指针
当然,不使用动态分配而采取原始指针(raw pointer)的用法也很常见,但是大多数情况下动态分配可以取代指针,因此一般情况应该首选动态分配的方法,除非你遇到不得不用指针的情况。
-
使用引用语义(reference semantics)的情况。有时你可能需要通过传递对象的指针(不管对象是如何分配的)以便你可以在函数中去访问/修改这个对象的数据(而不是它的一份拷贝),但是在大多数情况下,你应该优先考虑使用引用方式,而不是指针,因为引用就是被设计出来实现这个需求的。注意,采用这种方式,对象生存期依旧在其作用域内自维护。当然,如果通过传递对象拷贝可以满足要求的情况下是不需要使用引用语义。
-
使用多态的情况。通过传递对象的指针或引用调用多态函数(根据入参类型不同,会调用不同处理函数)。如果你的设计就是可以传递指针或传递引用,显然,应该优先考虑使用传递引用的方式。
-
对于入参对象可选的情况,常见的通过传递空指针表示忽略入参。如果只有一个参数的情况,应该优先考虑使用缺省参数或是对函数进行重载。要不然,你应该优先考虑使用一种可封装此行为的类型,比如 boost::optional (或者std::optional,已经在 C++ 14 草案 n3797 14 中发布 )。
-
通过解耦编译类型依赖减少编译时间的情况。使用指针的一个好处在于可以用于前向声名(forward declaration)指向特定类型(如果使用对象类型,则需要定义对象),这种方式可以减少参与编译的文件,从而显著地提高编译效率,具体可以看 Pimpl idiom 用法。
-
与C库或C风格的库交互的情况。此时只能够使用指针,这种情况下,你要确保的是指针使用只限定在必要的代码段中。指针可以通过智能指针的转换得到,比如使用智能指针的get成员函数。如果C库操作分配的内存需要你在代码中维护并显式地释放时,可以将指针封装在智能指针中,通过实现 deleter 从而可以有效的地释放对象。
总结 一下就是跟程序运行的作用域有关还和指针的管理有管
什么是函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
那么这个指针变量怎么定义呢?虽然同样是指向一个地址,但指向函数的指针变量同我们之前讲的指向变量的指针变量的定义方式是不同的。例如:
int(*p)(int, int);
这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“*”,即(p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int()(int,int)。
所以函数指针的定义方式为:
函数返回值类型 (* 指针变量名) (函数参数列表);
“函数返回值类型”表示该指针变量可以指向具有什么返回值类型的函数;“函数参数列表”表示该指针变量可以指向具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。C++中引用&与取地址&的区别分析
C++中的引用&与取址&是很多初学者经常容易出错的地方
具体而言,一个是用来传值的 一个是用来获取首地址的
&(引用)==>出现在变量声明语句中位于变量左边时,表示声明的是引用.例如:
int &rf; // 声明一个int型的引用rf
&(取地址运算符)==>在给变量赋初值时出现在等号右边或在执行语句中作为一元运算符出现时表示取对象的地址.
在C++中,既有引用又有取地址,好多人对引用和取地址不是很清楚,因此也无法区分。其实他们的区别可以用一句话概括:和类型在一起的是引用,和变量在一起的是取址。下面我们通过实例具体了解一下
1)引用在赋值=的左边,而取地址在赋值的右边,比如:int a=3; int &b=a; //引用 int *p=&a; //取地址
2)和类型在一起的是引用,和变量在一起的是取址。 举例同样如上,还有下例:
int function(int &i) { } //引用
3)对于vector,上面2条同样适合
vector<int> vec1(10,1); //initialize vec1: 10 elements, every element's value is 1 vector<int> &vec2 = vec1; // vec2 is reference to vec1 vector<int> *vec3 = &vec2; //vec3 is addresss of vec1 and vec2
为什么要用引用
数据的集合没有办法通过一个参数全部传入函数内部,只能传递它们的指针,在函数内部通过指针来影响这些数据集合。
有的时候,对于整数、小数、字符等基本类型数据的操作也必须要借助指针,一个典型的例子就是交换两个变量的值。当一个指针变量指向结构体时,我们就称它为结构体指针。
第一种写法中,.的优先级高于*,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于*(pointer.memberName),这样意义就完全不对了。第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。
传递数组的内容->强制传递数组指针
传递聚合类型数据->引用Reference在 C/C++ 中,我们将 char、int、float 等由语言本身支持的类型称为基本类型,
将数组、结构体、类(对象)等由基本类型组合而成的类型称为聚合类型。引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。
引用的定义方式类似于指针,只是用&取代了*,语法格式为:
type &name = data;
type 是被引用的数据的类型,name 是引用的名称,data 是被引用的数据。
引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它数据,这有点类似于常量(const 变量)。
注意,引用在定义时需要添加&,在使用时不能添加&,使用时添加&表示取地址。C++引用作为函数参数
在定义或声明函数时,我们可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一份数据。如此一来,如果在函数体中修改了形参的数据,那么实参的数据也会被修改,从而拥有“在函数内部影响函数外部数据”的效果。
引用类型的函数形参请尽可能的使用 const
当引用作为函数参数时,如果在函数体内部不会修改引用所绑定的数据,那么请尽量为该引用添加 const 限制。C++引用作为函数返回值
其实引用只是对指针进行了简单的封装,它的底层依然是通过指针实现的,引用占用的内存和指针占用的内存长度一样,在 32 位环境下是 4 个字节,在 64 位环境下是 8 个字节,之所以不能获取引用的地址,是因为编译器进行了内部转换
-
引用必须在定义时初始化,并且以后也要从一而终,不能再指向其他数据;而指针没有这个限制,指针在定义时不必赋值,以后也能指向任意数据。
-
可以有 const 指针,但是没有 const 引用。
-
指针可以有多级,但是引用只能有一级,
-
指针和引用的自增(++)自减(–)运算意义不一样。对指针使用 ++ 表示指向下一份数据,对引用使用 ++ 表示它所指代的数据本身加 1;自减(–)也是类似的道理。
C++左值和右值
通常判断某个表达式(可以是字面量、变量、对象、函数的返回值等)是左值还是右值,最常用的有以下 2 种方法。
- 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值。举个例子:
int a = 5;
5 = a; //错误,5 不能为左值
其中,变量 a 就是一个左值,而字面量 5 就是一个右值。值得一提的是,C++ 中的左值也可以当做右值使用,例如:
int b = 10; // b 是一个左值
a = b; // a、b 都是左值,只不过将 b 可以当做右值使用- 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。
以上面定义的变量 a、b 为例,a 和 b 是变量名,且通过 &a 和 &b 可以获得他们的存储地址,因此 a 和 b 都是左值;反之,字面量 5、10,它们既没有名称,也无法获取其存储地址(字面量通常存储在寄存器中,或者和代码存储在一起),因此 5、10 都是右值。
注意,以上 2 种判定方法只适用于大部分场景。由于本节主要讲解右值引用,因此这里适可而止,不再对 C++ 左值和右值做深度剖析,感兴趣的读者可自行研究。左值引用
lvalue 是“loactor value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据,
rvalue 译为 “read value”,指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。- 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值。举个例子:
int a = 5;
5 = a; //错误,5 不能为左值
其中,变量 a 就是一个左值,而字面量 5 就是一个右值。值得一提的是,C++ 中的左值也可以当做右值使用,例如:
int b = 10; // b 是一个左值
a = b; // a、b 都是左值,只不过将 b 可以当做右值使用- 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。
以上面定义的变量 a、b 为例,a 和 b 是变量名,且通过 &a 和 &b 可以获得他们的存储地址,因此 a 和 b 都是左值;反之,字面量 5、10,它们既没有名称,也无法获取其存储地址(字面量通常存储在寄存器中,或者和代码存储在一起),因此 5、10 都是右值。
右值引用
右值引用,用 “&&” 表示。
int num = 10; //int && a = num; //右值引用不能初始化为左值 int && a = 10; 和常量左值引用不同的是,右值引用还可以对右值进行修改。例如: int && a = 10; a = 100; cout << a << endl; 程序输出结果为 100。
shared_ptr、unique_ptr、weak_ptr智能指针
C++ 智能指针底层是采用引用计数的方式实现的。简单的理解,智能指针在申请堆内存空间的同时,会为其配备一个整形值(初始值为 1),每当有新对象使用此堆内存时,该整形值 +1;反之,每当使用此堆内存的对象被释放时,该整形值减 1。当堆空间对应的整形值为 0 时,即表明不再有对象使用它,该堆空间就会被释放掉。
-
-
深入理解C语言指针
2019-09-28 08:36:51一、指针的概念 要知道指针的概念,要先了解变量在内存中如何存储的。在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为指针,就像酒店的门牌号一样。 1.1、变量和地址 先写一段... -
C++中对象和对象指针的区别
2018-12-24 11:44:12是对象指针,而不是指针对象。因为这个被公司大佬们搞得很尴尬!!! 相同点: 1. 都是地址的概念; 指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。 ★ 区别: 1. 指针是一个... -
数组指针——指向数组对象的指针
2020-04-20 22:52:49数组指针——指向数组对象的指针 数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以int arr[] = { 99,... -
对象指针数组的理解以及指针与对象的存储位置的理解
2019-03-19 17:34:50今天在研究infomap的源码的是否,发现里面定义了个Node的指针数组: Node **node = new Node*[Nnode]; for(i=0;i<Nnode;i++){ node[i]=new Node(i); degree[i]=0.0; } 对于Node **node = new Node*[Nnode]... -
C++死磕基础之指针篇(三)--对象指针的创建以及使用
2020-11-29 23:11:44在上一篇文章中已经介绍了C++对象指针的概念,本篇文章主要讲解对象指针的两种创建方式 C++对象指针简介:C++对象指针 一.定义对象的指针,对象指针指向类的实例化对象的地址 先来看一个示例: Test1.h #ifndef TEST... -
虚函数的三种调用方式——对象名、指针和引用
2019-05-04 16:42:53通过对象名调用虚函数,在编译阶段就能确定调用的是哪一个类的虚函数,所以属于静态关联,如果通过基类指针调用虚函数,在编译阶段无法从语句本身确定调用哪一个类的虚函数,只有在运行时,指针指向某一具体对象后,... -
C++ --- 对象指针
2022-03-21 15:42:27类的对象在初始化的时候会在内存中占有内存空间,既可以通过对象名,也可以通过对象地址来访问每个对象。(这时就用到了对象指针) 对象指针的声明: 语法形式: 类名*对象指针名; Point * pointer;//声明对象... -
数组名与指针的联系和区别(数组名不是指针,而是关于“数组类型”的一个对象或者说变量 )
2018-09-27 01:11:061.数组名不是指针,它是“数组类型”的一个对象或者变量(就好比int i中的i,CString str当中的str) 2.“数组类型”的对象可以隐式转化为指针(当它转化为指针时,实际上是转化为指向数组第一个元素的指针) 先来... -
Golang 函数返回类型是接口时返回对象的指针还是值
2019-06-06 11:24:55Interface 是一组抽象方法(未具体实现的方法,仅包含方法名参数返回值的方法)的集合,如果实现了 interface 中的所有方法,即该类型就实现了该接口。 注意: (1)接口中不能含有属性; (2)每种类型都能实现多个... -
数组名是一个指针常量吗?
2016-03-04 22:49:00数组名是一个指针常量这种观点来源于数组名在表达式计算中与指针的结果等效性。例如下面的代码: int a[10], *p = a, *q; q = a + 1; q = p + 1; 在效果上看,a + 1与 p + 1是相同的,这很容易给人一种... -
类里面对象和指针的区别
2018-07-30 15:42:07关于指针和对象的区别困扰很多初学者,现在我就用一些直白的语言描述,来帮助大家越过这个坑,希望对大家有所帮助。 Student* s1; s1 = new Student(); s1->set("111"); Student s2; s2.set... -
函数对象和函数指针
2019-06-16 22:08:16函数指针 ...声明方法:数据类型标志符 (指针变量名) (形参列表) int (*func) (int x); 这里的(*func)不能去掉括号,去掉括号就是返回值为int指针的函数声明。 一般用typedef: typedef i... -
对象数组和对象指针
2017-05-08 10:01:57类也是自定义的一种数据类型,当需要在一个类下创建多个对象时,可以采用对象数组的方法,具体格式: 类名 对象名[常数]。 下面是是一段测试程序,并通过构造函数把对象数组均初始化。 #include using ... -
C++之对象数组与对象指针
2018-10-23 19:07:59格式: 类名 数组名[下标表达式] 在建立数组时,同样要调用构造函数。有几个数组元素就要调用几次构造函数。 (1)当只需要一个参数时,在定义对象数组时可以直接在等号后面的花括号内提供实参;当需要多个参数时... -
Java 对象、引用和指针
2016-05-13 21:02:02这行代码创建了一个Person实例,也被称为Person对象,这个Person对象被赋给p变量。这行代码中实际产生了两个东西:一个是p变量,一个是Person对象。从Person类定义来看,Person对象应该包含两个实例变量,而变量是... -
c++ 对象作为参数,指针作为参数,引用作为参数
2020-04-02 12:31:46传引用:把实参对象名传给形参对象名,形参对象名就成为实参对象名的别名,实参和形参代表同一个对象,所以改变形参,就是改变实参对象的值. 传指针:将指向对象的指针作为函数的参数,形参是对象的指针,实参是对... -
C++ 构造函数与对象指针
2022-04-07 20:22:50内含知识点包括: 构造函数 对象指针 公用对象的保护(const) 食用愉快~ -
c++函数指针和函数对象
2019-04-07 17:29:05C++ 函数指针和函数类型一、 导述二、c++成员函数在内存中的存储方式新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个... -
【C语言基础】【指针就是地址吗?】
2020-03-28 15:11:38在C语言中,你要知道指针、指针变量、地址三者之间的关系吗? 【解析】 C语言中,“指针”这个概念说的就是地址,指针就是地址,地址是一个数值,用16进制来表示比如就是这个样子: 0X111FFFF 那么谁来保存这个0X... -
c++ 指向对象成员的指针
2018-05-13 14:17:27在c++中类是抽象的,没有实际内存,而对象是具体,是占有内存的,因此对象有地址,存放对象的起始地址的指针变量就是指向对象的指针变量。对象中的成员也是占有内存的,所以,存放对象成员的起始地址的指针变量就是... -
指向对象的常指针变量与指向常对象的指针变量区别
2017-01-13 20:02:241 指向对象的常指针变量与指向常对象的指针变量区别 Time * const p; //指向对象的常指针变量 p的值(p的指向)不能修改 const Time *p; //指向常对象的指针变量,p指向的类对象的值不能通过p来修改 1.1 ... -
指针:什么是指针?
2021-01-09 19:34:19概念 指针是C语言中的一种数据类型,T*,用该种类型定义的变量称为指针变量,该变量中存储的是一个地址 注:指针变量中存储的是一个...):使用一个指向结构体或对象的指针访问其内成员。 sizeof(指针):32位系统下占用 -
C语言-指针
2021-05-22 01:10:22除此之外,表示变量在内存中生命期范围存储期以及变量名也都是变量的重要属性。取址运算符-address operator单目运算符`&` `&a` 取得`a`的地址(生成指向a的指针)取址运算符&的功能是取得对象的地址。... -
数组名不等于指针
2016-02-15 18:09:17一直都以为数组名和指针是相同的含义,直到今天做C软件工程师笔试题,才恍然大悟,才发现它们之间存在着巨大的差异。题目如下: void example(char echo[]) { printf( "%d", sizeof(echo)); } ... -
c++学习笔记之指向对象的指针以及对象数组
2018-11-04 15:58:58用对象数组的方法对数据成员进行初始化。 #include<iostream> using namespace std; class box { public: box(int h=10,int w=12,int len=15):height(h),width(h),length(len){} int volume...