C++ 张骞为什么要出使西域同时使

为啥有时候要用(*pa)[i]有时候只能用pa[i] - C++当前位置:& &&&为啥有时候要用(*pa)[i]有时候只能用pa[i]为啥有时候要用(*pa)[i]有时候只能用pa[i]www.MyException.Cn&&网友分享于:&&浏览:0次为什么有时候要用(*pa)[i]有时候只能用pa[i]在main中使用array类,
std::array&double,4&&
然后定义了这样一个函数。
void&fill(std::array&double,4&&*&pa);
然后传导expenses
fill(&expenses);
为什么在fill中使用pa[i]时一定要加(*pa)[i]才有效?
而另外,我写了一个double[]版本。
在main中使用double,
double&expenses[4];
然后定义这样一个函数
void&fill(double&*&pa);
同样传导expenses,
fill(expenses);
//此时不可以使用&,因为expenses本身就是地址
为什么在fill中使用pa时不能加*了?变成*pa就无法使用!
难道说double不是类?array是类?一个是对象,一个不是对象吗?------解决思路----------------------引用:Quote: 引用:
函数定义的,需要传指针的!
void&fill(std::array&double,4&&*&pa);&
对啊,我传递的是指针啊。指针指向对象地址。。。。。。
我好像明白点什么了。
是不是这样说:
第一个指针指向对象的地址。所以要解除引用才是对象。
第二个指针本身就是对象,接触引用就变成了值。
如果第二个函数void&fill(double&*&pa);
传递时变成fill(&expenses),
那么也要解除引用?
第二个expenses不能取地址,它本来就是数组的首地址,不是变量,没有内存地址!------解决思路----------------------前者,传递的是进去的是指向指针的指针,所以pa是指向指针的指针地址,(*p)才是array数组的首地址,所以用(*pa)[i];
后者,则是直接传递的数组指针地址。
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案暂无相关解决方案Copyright & &&版权所有1.为什么要有new?
为什么要有new?为什么要动态创建对象?为什么有时候不用new,有时候又用new,比如:
// Cocos2d-x3.x的Value类,大家都很熟悉了
Value v&=&Value(100);
// Cocos2d-x的Sprite类,也很属性了
Sprite*&sp&=&new&Sprite();
为什么有些地方不用new,有些地方又要new呢?
这就涉及到自动存储和动态存储了。
2.自动存储(自动变量、局部变量)
自动,也叫做自动变量,比如int num = 10; 这个num就属于自动变量。
所谓自动,代表它会自动申请内存,也会自动释放内存,自动变量是保存在栈里的(后进先出)。
如果大家觉得很难理解,那么,换一个名称&&局部变量。
这个好理解了吧?局部变量在离开函数,或者离开它所属的代码块之后,就会被释放。
而Value v = Value(100); 、int num = 10; 这些都是局部变量,一旦离开函数或者离开它的作用域,就会被释放。
比如把 作为成员变量,那么,在这个类被释放的时候,num变量也会被释放。
这就是为什么我们在创建了这么多int、float等基本类型的变量之后,不需要去释放它们。
因为它们是自动被释放的。
3.动态存储
自动变量有很大的好处,那就是不需要我们去管方面的事情,但是,有时候我们不希望有这样的自动释放内存。
我们希望自己去控制什么时候释放对象,这时候就要用到new了。
我们都知道,new了之后,如果不调用相应delete的话,申请到的内存空间是永远都不会被释放的。
这就是动态了,我们自己来申请内存,自己来释放内存。
当然,内存泄露的罪魁祸首之一也正是new~!
因为正常人都会有疏忽的时候,并且当程序足够庞大、逻辑足够复杂的时候,有些地方调用了new,却疏忽了delete是再正常不过了。
当然,new的作用也许不仅于此,书上目前还没深入介绍,我也不多说,免得说错,毕竟C++还是需要严谨一些的~
我不敢乱吹水~
阅读(...) 评论()为什么我们今天还要学习 C++? - 知乎282被浏览<strong class="NumberBoard-itemValue" title="8,394分享邀请回答247 条评论分享收藏感谢收起66 条评论分享收藏感谢收起为什么我们要使用c++的前置声明 - 简书
为什么我们要使用c++的前置声明
转载声明:() 。
感谢原作者的辛勤付出。
定义一个类 class A,这个类里面使用了类B的对象b,然后定义了一个类B,里面也包含了一个类A的对象a,就成了这样:
#include "b.h"
#include "a.h"
一编译,就出现了一个互包含的问题了,这时就有人跳出来说,这个问题的解决办法可以这样,在a.h文件中声明类B,然后使用B的指针。
//#include "b.h"
#include "a.h"
然后,问题就解决了。
但是,有人知道问题是为什么就被解决的吗,也就是说,加了个前置声明为什么就解决了这样的问题。下面,让我来探讨一下这个前置声明。
类的前置声明是有许多的好处的。
我们使用前置声明的一个好处是,从上面看到,当我们在类A使用类B的前置声明时,我们修改类B时,只需要重新编译类B,而不需要重新编译a.h的(当然,在真正使用类B时,必须包含b.h)。
另外一个好处是减小类A的大小,上面的代码没有体现,那么我们来看下:
我们看上面的代码,类B的大小是12(在32位机子上)。
如果我们在类A中包含的是B的对象,那么类A的大小就是12(假设没有其它成员变量和虚函数)。如果包含的是类B的指针*b变量,那么类A的大小就是4,所以这样是可以减少类A的大小的,特别是对于在STL的容器里包含的是类的对象而不是指针的时候,这个就特别有用了。
在前置声明时,我们只能使用的就是类的指针和引用(因为引用也是居于指针的实现的)。
1)降低模块的耦合。因为隐藏了类的实现,被隐藏的类相当于原类不可见,对隐藏的类进行修改,不需要重新编译原类。
2)降低编译依赖,提高编译速度。指针的大小为(32位)或8(64位),X发生变化,指针大小却不会改变,文件c.h也不需要重编译。
3)接口与实现分离,提高接口的稳定性。
1、通过指针封装,当定义“new C”或"C c1"时 ,编译器生成的代码中不会掺杂X的任何信息。
2、当使用C时,使用的是C的接口(C接口里面操作的类其实是pImpl成员指向的X对象),与X无关,X被通过指针封装彻底的与实现分离。
那么,我问你一个问题,为什么我们前置声明时,只能使用类型的指针和引用呢?
如果你回答到:那是因为指针是固定大小,并且可以表示任意的类型,那么可以给你80分了。为什么只有80分,因为还没有完全回答到。
想要更详细的答案,我们看下下面这个类:
A(int a):_a(a),_b(_a){} // _b is new add
int get_a() const {return _a;}
int get_b() const {return _b;} // new add
int _b; // new add
我们看下上面定义的这个类A,其中_b变量和get_b()函数是新增加进这个类的。
那么我问你,在增加进_b变量和get_b()成员函数后这个类发生了什么改变,思考一下再回答。
好了,我们来列举这些改变:
1.第一个改变当然是增加了_b变量和get_b()成员函数;
2.第二个改变是这个类的大小改变了,原来是4,现在是8。
3.第三个改变是成员_a的偏移地址改变了,原来相对于类的偏移是0,现在是4了。
4.上面的改变都是我们显式的、看得到的改变。还有一个隐藏的改变,想想是什么。。。
这个隐藏的改变是类A的默认构造函数和默认拷贝构造函数发生了改变。
由上面的改变可以看到,任何调用类A的成员变量或成员函数的行为都需要改变,因此,我们的a.h需要重新编译。
如果我们的b.h是这样的:
#include "a.h"
那么我们的b.h也需要重新编译。
如果是这样的:
那么我们的b.h就不需要重新编译。
像我们这样前置声明类A:
是一种不完整的声明,只要类B中没有执行需要了解类A的大小或者成员的操作,则这样的不完整声明允许声明指向A的指针和引用。
而在前一个代码中的语句
是需要了解A的大小的,不然是不可能知道如果给类B分配内存大小的,因此不完整的前置声明就不行,必须要包含a.h来获得类A的大小,同时也要重新编译类B。
再回到前面的问题,使用前置声明只允许的声明是指针或引用的一个原因是只要这个声明没有执行需要了解类A的大小或者成员的操作就可以了,所以声明成指针或引用是没有执行需要了解类A的大小或者成员的操作的。
二、使用总结
这篇文章很大程度是受到Exceptional C++ (Hurb99)书中第四章 Compiler
Firewalls and the Pimpl Idiom
(编译器防火墙和Pimpl惯用法) 的启发,这一章讲述了减少编译时依赖的意义和一些惯用法,其实最为常用又无任何副作用的是使用前置声明来取代包括头文件。
Item 26 的Guideline - "Never #include a header when a forward declaration will suffice"
在这里,我自己总结了可以使用前置声明来取代包括头文件的各种情况和给出一些示例代码。
首先,我们为什么要包括头文件?问题的回答很简单,通常是我们需要获得某个类型的定义(definition)。那么接下来的问题就是,在什么情况下我们才需要类型的定义,在什么情况下我们只需要声明就足够了?问题的回答是当我们需要知道这个类型的大小或者需要知道它的函数签名的时候,我们就需要获得它的定义。
假设我们有类型A和类型C,在哪些情况下在A需要C的定义:
1.A继承至C
2.A有一个类型为C的成员变量
3.A有一个类型为C的指针的成员变量
4.A有一个类型为C的引用的成员变量
5.A有一个类型为std::list&C&的成员变量
6.A有一个函数,它的签名中参数和返回值都是类型C
7.A有一个函数,它的签名中参数和返回值都是类型C,它调用了C的某个函数,代码在头文件中
8.A有一个函数,它的签名中参数和返回值都是类型C(包括类型C本身,C的引用类型和C的指针类型),并且它会调用另外一个使用C的函数,代码直接写在A的头文件中
9.C和A在同一个名字空间里面
10.C和A在不同的名字空间里面
1.没有任何办法,必须要获得C的定义,因为我们必须要知道C的成员变量,成员函数。
2.需要C的定义,因为我们要知道C的大小来确定A的大小,但是可以使用Pimpl惯用法来改善这一点,详情请
看Hurb的Exceptional C++。
3.4.不需要,前置声明就可以了,其实3和4是一样的,引用在物理上也是一个指针,它的大小根据平台不同,可能是32位也可能是64位,反正我们不需要知道C的定义就可以确定这个成员变量的大小。
5.不需要,有可能老式的编译器需要。标准库里面的容器像list, vector,map,
在包括一个list&C&,vector&C&,map&C, C&类型的成员变量的时候,都不需要C的定义。因为它们内部其实也是使用C的指针作为成员变量,它们的大小一开始就是固定的了,不会根据模版参数的不同而改变。
6,不需要,只要我们没有使用到C。7,需要,我们需要知道调用函数的签名。8,8的情况比较复杂,直接看代码会比较清楚一些。
C& doToC(C&);
C& doToC2(C& c) {return doToC(c);};
从上面的代码来看,A的一个成员函数doToC2调用了另外一个成员函数doToC,但是无论是doToC2,还是doToC,它们的的参数和返回类型其实都是C的引用(换成指针,情况也一样),引用的赋值跟指针的赋值都是一样,无非就是整形的赋值,所以这里即不需要知道C的大小也没有调用C的任何函数,实际上这里并不需要C的定义。
但是,我们随便把其中一个C&换成C,比如像下面的几种示例:
1.C& doToC(C&);
C& doToC2(C c) {return doToC(c);};
2.C& doToC(C);
C& doToC2(C& c) {return doToC(c);};
3.C doToC(C&);
C& doToC2(C& c) {return doToC(c);};
4.C& doToC(C&);
C doToC2(C& c) {return doToC(c);};
无论哪一种,其实都隐式包含了一个拷贝构造函数的调用,比如1中参数c由拷贝构造函数生成,3中doToC的返回值是一个由拷贝构造函数生成的匿名对象。因为我们调用了C的拷贝构造函数,所以以上无论那种情形都需要知道C的定义。
9和10都一样,我们都不需要知道C的定义,只是10的情况下,前置声明的语法会稍微复杂一些。
最后给出一个完整的例子,我们可以看到在两个不同名字空间的类型A和C,A是如何使用前置声明来取代直接包括C的头文件的:
#pragma once
#include &list&
#include &vector&
#include &map&
#include &utility&
//不同名字空间的前置声明方式
namespace test1
namespace test2
//用using避免使用完全限定名
using test1::C;
C& doToC(C&);
C& doToC2(C& c) {return doToC(c);};
std::list&C&
std::vector&C&
std::map&C, C&
#ifndef C_H
#define C_H
#include &iostream&
namespace test1
void print() {std::cout&&"Class C"&&std::}
前言 把《C++ Primer》读薄系列笔记全集。 目录 第I部分:C++基础 开始学习C++ 变量和基本类型 字符串、向量和数组 表达式 语句 函数 类 第II部分:C++标准库 IO库 顺序容器 范型算法 关联容器 动态内存 第III部分:类设计者的工具 拷贝控制 重载...
C语言笔记 一终端命令 ls -l显示当前工作路径下的所有的文件及文件信息 d开头文件夹 -开头文件 r读 w写 x执行 - -当前用户的权限 - -其他用户的权限 & pwd查看终端程序的工作路径 &cd切换工作路径 &clear清理屏幕 &touch新建文件 &open...
重新系统学习下C++;但是还是少了好多知识点;socket;unix;stl;boost等; C++ 教程 | 菜鸟教程http://www.runoob.com/cplusplus/cpp-tutorial.html $ g++ -vConfigured with: --...
在C++11中,我们还是会看到一些新元素。这些新鲜出炉的元素可能会带来一些习惯上的改变,不过权衡之下,可能这样的改变是值得的。 指针空值 — nullptr 指针空值:从0到NULL,再到nullptr 在良好的C++编程习惯中,声明一个变量的同时,总是需要记得在合适的代码...
C++文件 例:从文件income. in中读入收入直到文件结束,并将收入和税金输出到文件tax. out。 检查文件是否成功打开 常量 C++中的const变量能在任何常数可以出现的地方使用,例如数组的大小、case标号中的表达式。 bool data type C++新...
1.当你变成你最好的样子的时候,那么你等的人就会出现了。 你是不是总是在怨天尤人,又是否总是在为自己找借口。我不想说我想成为什么样的人,我只想做好我自己。 我的一位朋友,她上初中成绩不大好,上不了重点中学。她就去学习画画,打算考我们当地的艺术中学。很可惜,当时她的艺术单招考...
每天放学回家,我都会经过一家小商店,虽然店小,里面的东西却很多。 有一天,我放学回家时,在商店门前停住了脚步,因为我闻到了一股香味,这香味直让我流口水。我明白这香味来自一种东西---辣条! 妈妈从来不让我吃辣条,不过今天我决定,明天一定要带钱来买辣条。 第二天,好不容易熬到...
回望2016年,微商已进入品牌化的一年,告别了微商初期空白市场下的“产品为王”,也告别了爆款时代。随着微商的日益规范,微商从业人数已经突破了3000万,创造的产值也超过了5000亿。在2107年这个拐口,微商该如何把握趋势赢战未来?由微谷教育精心打造的《中国微商操盘手》将给...
以下是我对新零售趋势的观察和思考,在此分享出来,想与各位同学一起学习一起进步。 我对零售业态的理解有两种业态,一种是卖产品,比如消费品;另外一种是售卖服务,比如健身房、游乐设施、培训教育。 服务型商家售卖的核心是时间,服务质量并非标准化;而产品型商家售卖的单位是数量(SKU...
目前市场上的零售门店有很多种,竞争也是非常激烈的。因此一些门店就会时常搞促销活动,那么零售门店的促销方式有哪些呢?今天小编整理了下面两方面的促销方式供大家参考。 常规促销 1.折扣促销:折扣是零售店常见的促销方法,有百分之三十五点八的消费者接受过此类方式。 2.卡式促销:卡...

我要回帖

更多关于 魏王为什么要追杀此使 的文章

 

随机推荐