面向对象设计还需要指针么?

作者:小菜 更新时间:2025-03-16 点击数:
简介:大三那会还在搞单片机和MFC,玩的纯C系的语言,每天和指针打交道,一切皆指针。

有一天,听说JAVA里没有了指针,我大惊失色,指针都没了,这语言还能搞啥? 后来,

【菜科解读】

大三那会还在搞单片机和MFC,玩的纯C系的语言,每天和指针打交道,一切皆指针。

有一天,听说JAVA里没有了指针,我大惊失色,指针都没了,这语言还能搞啥?

后来,类似C#,JAVA的高级面向对象语言用得多了。

反过来思考,高级面向对象语言没有了指针,到底是好事还是坏事?这种区别体现在哪里?本文以C#和C++为例做个对比,JAVA机制和C#类似。

与各位共同探讨。

为了简单,我们先定义一个Point类, 只有X,Y 两个变量。

看看C++和C#之间的使用区别

1. 指针和引用

C++中,指针和引用的有一定的区别,指针是一个地址,而引用只是别名,引用使用起来要方便得多。

因为指针本身是地址,地址当然可以指向任何地方,所以便有了指针的指针,如果再和数组,函数,结构和类联系上,那简直就是考验人的大脑。

C++的引用,定义了就必须在声明时就初始化,而且不能更改。

C#中,只有引用,一切“引用型变量”都是引用。

但这个引用和C++中的引用不同,它更像一个“地址”。

如果你声明了 Point p, p就是引用。

但是这个p可能没有初始化,你也可以在任何时候改变它。

点评: 指针本来是好东西,但它太灵活,搞得太复杂了。

反正我现在不大喜欢看*和&这类符号。

2.类的构造

C++中,可以使用两种方式新建一个变量:

(1) Point p, 你就构造了一个Point变量。

它处在栈区。

(2) Point* p=new Point; 它处在堆区:

最牛的在于,Point points[10]; 这样的声明,会直接产生十个Point对象,处于栈区。

也可以这么定义,Point* ps=new Point[10]; 处于堆区。

C#中,只有一种方式创建:Point p=new Point(); 处于堆区。

3. 交换两个对象

大家一定都记得,初学C++时经典的数字交换问题。

C++中, 两种做法: void Swap(int* a,int *b) 或者是 void Swap(int& a,int& b) ,这个没什么好说的

有意思的是,如果交换两个对象呢? 如果是void Swap(Point a, Point b),那你就已经错了,在执行这个函数时,拷贝构造函数会将你的实参分别拷贝到a,b两个对象中,处在堆区。

当函数返回时,你除了浪费了一堆时间做无谓的拷贝工作外,对象还是原来的对象。

因此还得是 void Swap(Point* a, Point *b)或者 void Swap(Point& a, Point& b)。

C#中,交换值类型时,可以使用void Swap(ref int a, ref int b), 如果是引用类型,直接使用void Swap(Point a, Point b)就行了。

点评:你会发现,C++中根本就没有值类型和引用类型这回事,加上*,&才是“引用类型”,否则就是值类型,值类型传递,就会调用拷贝构造函数,造成一定的性能损失。

而C#不存在这个问题。

4.函数返回值与工厂模式

设计模式的构造模式中,工厂是最常见的,你可以非常方便的写一个C#版本的工厂,但在C++中,怎么实现工厂?

Point GetProduct(){Point p; //设置为默认值就可以了。

returnp;}

调用时 Point *p= &GetProduct();

你觉得这样对么?留给读者讨论。

5.类的组合和对象拷贝

类可以组合,也可以继承。

但在C++中,类组合会带来额外的问题,考虑如下的结构:

classPointEx{public:Point A;Point B;//其他成员和函数}

那么你声明一个PointEx pex, 那么A,B两个对象就会被自动创建。

如果希望能在构造函数中传递A,B两个类的参数,那必须使用“内部对象构造函数”,具体细节参考普通C++教材。

而对象拷贝时,也带来了额外的隐患,默认的拷贝构造函数只能拷贝普通类型,但这些组合的成员,如果直接=的话,那么两个PointEx可能就指向同一个Point A。

在C#中,不存在这样的问题,首先A,B在PointEx的构造中,根本就不会被构造。

除非你在PointEx中显式的new出A和B。

除此之外,C++中,子类和父类的构造函数与析构函数的执行顺序相当重要。

C#中,析构函数被取消了(因为GC),代之以Dispose模式。

6. 函数指针和委托

首先,函数指针是无敌强大的,因为存储区分为堆,栈,代码区和全局数据区。

所以代码区也是能被指针访问的,因此函数指针指向代码区,就能把函数流程指向那个区域。

这是函数指针的实质。

C++中:你可以这样定义函数指针 int (*sqrt) (int x); (看着真恶心,你还没见函数指针数组,返回函数指针的函数等等丧心病狂的类型) 。

可以这样赋值:

先随便定义一个函数sqrt2, 然后func= sqrt2;就可以了,

C#中:可以这样定义委托 delegate int sqrt(int x); 赋值类似。

当然还有更牛的“事件”,实现了多播委托(我理解就是委托数组)

点评: 委托的最大好处是强类型的,而且看着比函数指针优雅的多,功能也更强。

最近,我认识到了函数式编程的强大。

如果能认识到“函数也是变量”,那么就是一个很大的进步。

7. 指针类型转换

先说普通值类型的指针类型转换。

C++中:定义两个指针, int*a 和float*b . 两个是不能直接赋值的。

要想赋值,只能采用空指针作为中介:

void*pv= a; b= static_cast(pv);

如果是对象,而且是有继承关系的,例如Point3D继承于Point,那么从Point*到Point3D*如何转换呢?

C#中,可以采用强制类型转换或as关键字:

Point3D p3d= (Point3D)p2d; 或者是 Point3D p3d= p2d as Point3D;

点评:类型是任何一门语言中都非常复杂的一部分。

C#有强大得多的类型系统和元数据模型,处理起来要更高级一些。

不过,我有个疑问,C++中,什么区域存储一个变量的类型?机器怎么知道某一块区域内的内存是int而不是double? 难道存储在代码区?

8. 类和结构体的区别

C++中,类和结构体本质几乎没有区别,结构体也能定义函数,定义不同的变量成员,只是所有成员都是公开的;而类有访问控制,可以实现继承和派生。

C#中:类是引用类型,结构体是值类型。

结构体作为参数或返回值,都需要做拷贝。

而且,结构体无法定义除了构造函数之外的成员函数。

用结构体,可以获得比类更高的性能。

导致这些区别的原因:内存分配

其实,说这么多,导致C#和C++的 这些区别的本质原因,在于它们内存分配机制的不同。

C++中,不论是对象还是普通的值,如果是通过 Point p这样的语法生成的话,那么就在栈上。

一旦函数结束,栈就被回收。

只有new关键字生成的对象,才放在堆上。

放在栈上的数据因为随时可能被回收,才需要这么复杂的指针机制。

指针的地址问题,这就像装盒子一样,一个盒子不安全,就多套几层盒子,盒子越套越多,搞得越来越复杂。

C#中,有值类型和引用类型的区别。

所有的引用类型,都在堆上,回收靠GC处理。

普通函数中定义的值类型都在栈上。

如果是对象当中的“值”,那当然也定义在堆上。

因为堆比栈方便多了,一个地址就可以了。

所以使用起来要比在栈上方便的多。

要说性能,当然是栈比堆快,和内存访问的集中性有关,栈的数据基本都在高速缓存当中,命中率极高。

但堆却不一定。

正是因为GC的作用,允许引用类型就定义在堆上。

当然,我相信对于C#这样的语言,在编译或运行时应该会计算哪些是数据访问热点,从而优化命中率。

C#这类高级语言,是靠一个强大的“运行时”(runtime)和虚拟机来帮助它实现了这类区别。

我现在还不是很清楚,堆和栈的比例是怎么分配的。

以前搞单片机的时候,会有一个编译选项选择它们的比例,我一般会把栈内存(heap)拉到90%,我不愿意用堆,因为觉得麻烦。

那么,高级面向对象语言需要指针么?

有了上面的那一段,估计大家都有答案了。

因为有了强大的运行时支持,有了垃圾回收器,使得堆的使用率比栈大的多。

虽然性能上会有那么一点点损失吧,但带来的确实是代码的简洁,高效,程序员再也不需要玩指针的游戏了。

它带来了以下好处:

1. 省略了拷贝构造函数和析构函数

2. 简化了函数的参数和返回值,不需要再去调用拷贝函数了,性能有所提升。

3. 简化了对象组合的复杂性,C++内存管理本来就够复杂了,面向对象会变得更加复杂,稍微不注意就会造成内存泄露和指针悬挂等。

而在C#中,你可以放心大胆的使用组合和继承。

思路会清晰的多。

4.C#,JAVA代码好看得多,起码没有那些奇怪的符号。

5. 其他我还没有想到的好处。

从这个角度来说,指针的作用已经被“引用”类型代替了。

但是,C++不需要运行时和虚拟机,直接编译为原生代码,性能肯定更好,但确实C++难学。

C++大牛肯定能列出一堆C++内存机制的好处,这个见仁见智了。

还有些遗留的问题,当开启C#的unsafe选项后,可以在C#里直接写C++,那么这种内存管理是如何完成的?

面向,对象,设计,还,需要,指针,么,大三,那会,

搭讪的人不是单身办?搭讪知道对方有没有对象

当我们遇到喜欢的人时会想要忍不住上前搭讪,只是相信很多人在搭讪之前应该都有过这样的顾虑,那就是万一人家不是单身怎么办?那自己岂不是会很尴尬?搭讪的人不是单身怎么办?当你在外面搭讪别人时,要如何判断对方有没有男女朋友呢?一般来说,如果你抱着比较明显的意图去搭讪异性的时候,对方若不是单身,他会礼貌拒绝你的。

举个例子,男生在外面遇到了个长得比较漂亮的女孩子,他忍不住上前搭讪,希望能够要到对方的微信,但是女孩已经有男朋友了,这种时候被搭讪的女生可能就会礼貌拒绝男生,跟对方说自己已经有男朋友了。

所以说,搭讪的对象是不是单身,有时候只有你上前搭讪了才知道。

如果对方真的是你很喜欢的类型,那你也不要有太多的顾虑和担心,即便对方真的不是单身了,那又怎样?成功与否只有上前搭讪了才知道结果,你若是畏畏缩缩,那你恐怕也就真的没有机会了。

如果你搭讪的时候遇到不是单身的人,而且还被人家拒绝了,那你也不要觉得羞赧和没面子,可以大大方方离开,也可以尝试着跟对方交个朋友。

若是实在怕被人家拒绝,可以在搭讪的时候表现得委婉点,不要把喜欢对方的意图表现得那么明显。

比如找借口向对方请教问题,找对方问个路,顺便在这个过程中衍生出一些其他的话题,去试探性跟对方聊聊天,看对方是什么态度。

搭讪一个陌生人的时候,我们往往很难在第一时间判断出对方有没有对象。

但你可以从对方身上的一些小细节上,判断他是否有对象。

比如看他手上有没有戴戒指,比如看他当时有没有在跟别人打电话,或者在等别人等等,如果人家真的有对象了,那你就不要再纠缠打扰人家了。

精美PS边框素材,让你的设计更加出众!

专业的在线重装系统软件 全新设计 / 全新代码编写 / 全新支持所有机型 全新支持Window 11 安装 简介:精美PS边框素材,让你的设计更加出众!在设计中,边框素材是非常重要的元素之一,它可以为作品增添一份精致和独特的风格。

然而,寻找适合自己的边框素材并不容易,有时候花费大量时间却无法找到满意的效果。

为了解决这个问题,我整理了一些精美的PS边框素材,希望能够帮助大家提升设计的品质和水平。

工具原料:系统版本:Windows 10品牌型号:Dell XPS 15软件版本:Adobe Photoshop CC 2021一、边框素材的分类和选择1、边框素材可以分为简约、复古、花纹等多种风格,根据自己的设计需求选择合适的风格。

2、在选择边框素材时,要考虑作品的整体风格和色彩搭配,确保边框与作品相互协调。

二、边框素材的下载和使用1、可以通过设计资源网站或者PS插件来下载边框素材,确保素材的质量和版权合法。

2、下载后,将边框素材导入到PS软件中,可以通过调整大小、旋转等操作来适应作品的需要。

三、边框素材的搭配和创意运用1、可以将不同风格的边框素材进行组合,创造出独特的效果,提升作品的视觉冲击力。

2、可以通过调整边框的透明度、叠加模式等属性,使边框与作品更加融合,增强整体效果。

四、边框素材的自定义和个性化1、可以根据自己的需求,对边框素材进行自定义修改,如改变颜色、添加纹理等,使其更符合作品的风格。

2、可以利用PS的各种工具和滤镜效果,对边框素材进行进一步的处理和创作,实现更多的设计可能性。

总结:通过使用精美的PS边框素材,我们可以为作品增添一份独特的风格和个性,使设计更加出众。

在选择、下载、搭配和自定义边框素材时,我们需要考虑作品的整体需求和风格,灵活运用各种技巧和工具,创造出令人惊艳的效果。

希望这些边框素材能够帮助大家提升设计水平,创作出更加精美的作品。

加入收藏
               

面向对象设计还需要指针么?

点击下载文档

格式为doc格式

  • 账号登录
社交账号登录