C++中为什么int a=3;泰国double a公司&b=a;这样不能类型转换,加了一个const后就可以将a转换为b了

C++中为什么临时对象的引用一定要加就像: const string& s = string(&abc&); 求详解_百度知道
C++中为什么临时对象的引用一定要加就像: const string& s = string(&abc&); 求详解
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
sailingzyf
sailingzyf
采纳数:545
获赞数:925
iamchenmin
所说,有防止修改的功能。另,1、考虑如下函数定义:int fun2(int& pi){}因为没有修改pi,所以参数就懒得加const限制,但在其他地方调用次函数时会有限制:非const的引用参数必须用与其类型一致的对象/量来初始化,也就是说可以这样用:int a=5;b=fun2(a);这样:int b=fun2(5);是错的。因为数字5是一个字面值,也就是个右值,而函数要求的是一个具体的int类型的对象/变量,需要左值。然后这样:long a=5;int b=fun2(a);也不行,类型不一样。但参数加上const后上两种都是合法的,const引用的参数允许可行的转换,比如fun2(3.14),参数是个浮点,但编译器会转换成int然后调用,要是压根转换不过去那肯定加了const也不行的。2、另外,即使说,我所有代码为了易读,绝对不会出现字面值这东西,还有个问题。如果你写了个函数为了保护参数加了const,但函数里面调用了另一个参数没const的函数,那么这里估计就要出错,const实参不能传递给非const形参。虽然你能保证自己的代码不冲突,但不能保证别人的代码,尤其是合作的时候每人写一个部分。3、综上,不需要改动的参数,如果要通过引用传递,全都加上const最安全。ps:你所说的“强制要求添加的”,实际上并不是强制,因为加不加是作者自己的意思,而编译错误都是出在调用的语句,也就是使用者错了 o(∩_∩)o...
iamchenmin
iamchenmin
采纳数:202
获赞数:916
擅长:暂未定制
防止被修改。&不管是临时对象还是函数调用,只要不涉及对对象的修改,一般都推荐加上const。&比如,C语言里的string.h对strcpy的声明就是这样的,char&*strcpy(char&*ori,const&char&*src)在后面的src加上了const,视其为常量,使它只能被读取而不能被修改。&总结就一句话,防止有意的或者无意的修改。
如果仅仅是防止无意的修改,那么应该是编写程序的人有选择的添加const吧,但这个是强制要求添加的,不加const编译都会失败;
本回答被网友采纳
为你推荐:
其他类似问题
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。博客分类:
reinterpret_cast,const_cast,static_cast,dynamic_cast 显式类型转换
#include&iostream.h&
int main(void)
//reinterpret_cast
//将一个类型指针转换为另一个类型指针,这种在转换不修改指针变量值数据存放格式
//只需在编译时重新解释指针的类型,他可以将指针转化为一个整型数但不能用于非指针的转换
double d=9.3;
double* pd = &d;
int* pi = reinterpret_cast&int *& (pd);
class A{};
class B{};
A* pa = new A;
B* pb=reinterpret_cast&B*&(pa); //将pa 转为B
long j=reinterpret_cast&long& (pa);//指针转换为整数
// int i=9;
// double x=reinterpret_cast&double&(i); //reinterpret_cast不能用于非指针的转换
//const_cast
//1.用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,
//2.反过来也可以将一个非常量指针转换为一个常量指针变量
//3.他无法将一个非指针的常量转换为普通变量
//example: const i=10;
int j=const_cast&int&(i); //无法转换
const int ppp=998;
const int* pca=&
int* p=const_cast&int*&(pca);//将它转换为一个对应指针类型的普通变量,去除了
const A* paa=new A;
A * ppppa=const_cast&A*& (paa);//它转换为一个对应指针类型的普通变量,去除了
int * pii=0;//反过来也可以将一个非常量指针转换为一个常量指针变量
const int* piiic=const_cast&const int *&(pii);
//////////////////////////////////////////////////////////////////////////////////
//static_cast
//用于转换基本类型和具有继承关系的类新之间转换
//static_cast不太用于指针类型的之间的转换,他的效率没有reinterpret_cast的效率高
int in=99;
double dn=static_cast&double& (in);//用于转换基本类型和具有继承关系的类新之间转换
class Base{};
class derv:public Base{};
Base bbbb=static_cast&Base&(dd);//具有继承关系的类型之间转换
//static_cast不太用于指针类型的之间的转换,他的效率没有reinterpret_cast的效率高
Base *pb1=new B
derv *pder=static_cast&derv*&(pb1);//基类转继承类
derv* pder1=
Base* pbase1=static_cast&Base*&(pder1);//继承类指针转父类指针
//////////////////////////////////////////////////////////////////////////
//dynamic_cast
//1.只能在继承类对象的指针之间或引用之间进行类型转换
//2.这种转换并非在编译时,而是在运行时,动态的
//3.没有继承关系,但被转换的类具有虚函数对象的指针进行转换
Base* bv=dynamic_cast&Base *&(dp);//继承类对象的指针之间进行类型转换
//继承类对象引用之间进行类型转换
Base &b=dynamic_cast&Base&&(dpp);
class AA{virtual fun(){}
virtual ~AA(){}};
class BB{};
//没有继承关系,但被转换的类具有虚函数对象的指针进行转换,编译可通过
AA* pAA=new AA;
BB* pBB=dynamic_cast&BB *&(pAA);
//没有继承关系,被转换的类也没有有虚函数对象的指针进行转换,编译不能通过
BB* pBBB=new BB;
AA* pAAA=dynamic_cast&AA*&(pBBB);
reinterpret_cast 将一个类型指针转换为另一个类型指针
const_cast&&& 用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,反过来也可以将一个非常量指针转换为一个常量指针变量
static_cast&&& 用于转换基本类型和具有继承关系的类新之间转换,不太用于指针类型的之间的转换
dynamic_cast&&& 只能在继承类对象的指针之间或引用之间进行类型转换
以上只有dynamic_cast这种转换并非在编译时,而是在运行时,动态的。其它均在编译时
——————————————————————————————————————
标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。
static_cast
用法:static_cast & type-id & ( exdivssion )
该运算符把exdivssion转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类和子类之间指针或引用的转换。
  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉exdivssion的const、volitale、或者__unaligned属性。
dynamic_cast
用法:dynamic_cast & type-id & ( exdivssion )
该运算符把exdivssion转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;
如果type-id是类指针类型,那么exdivssion也必须是一个指针,如果type-id是一个引用,那么exdivssion也必须是一个引用。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,
dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
class B{
virtual void foo();
class D:public B{
char *m_szName[100];
void func(B *pb){
D *pd1 = static_cast&D *&(pb);
D *pd2 = dynamic_cast&D *&((pb);
在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;
但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),
而pd2将是一个空指针。
另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。
这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(
关于虚函数表的概念,详细可见)中,只有定义了虚函数的类才有虚函数表,
没有定义虚函数的类是没有虚函数表的。
另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。
class A{
virtual void f(){}
class B:public A{
class D:public A{
void foo(){
B *pb = new B;
pb-&m_iNum = 100;
D *pd1 = static_cast&D *&((pb); //compile error
D *pd2 = dynamic_cast&D *&((pb); //pd2 is NULL
在函数foo中,使用static_cast进行转换是不被允许的,
将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。
reinterpret_cast
用法:reinterpret_cast& type-id &(exdivssion)
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,
在把该整数转换成原类型的指针,还可以得到原先的指针值)。
该运算符的用法比较多。
const_cast
用法:const_cast& type-id & (exdivssion)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和exdivssion的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
Voiatile和const类试。举如下一例:
class B{
void foo(){
const B b1;
b1.m_iNum = 100; //comile error
B b2 = const_cast&B&((b1);
b2. m_iNum = 200; //fine
上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;
使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。
浏览: 703302 次
来自: 太原
感谢楼主,查了半天终于发现居然是htmlentities()做 ...
这本书的名字 有谁知道????~~~
怎么下载啊
没有内容啊
谢谢先 先看看
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'以下试题来自:
单项选择题下列语句中错误的是A.const int a;B.const int a=10;C.const int*point=0;D.const int*point=new int(10);
为您推荐的考试题库
你可能感兴趣的试题
1A.顺序存储结构的存储一定是连续的,链式存储结构的存储空间不一定是连续的B.顺序存储结构只针对线性结构,链式存储结构只针对非线性结构C.顺序存储结构能存储有序表,链式存储结构不能存储有序表D.链式存储结构比顺序存储结构节省存储空间2A.iostreamB.fstreamC.strstreamD.iomanip3A.f( )是基类的私有成员B.f( )是基类的保护成员C.派生类的继承方式为私有D.派生类的继承方式为保护4A.N-S图B.DFD图C.PAD图D.程序流程图5A.void fun(int a=90,double b=0.0);B.int fun(int a,doubleB) ;C.vD.bool fun(int a,double b=0.0);
热门相关试卷
最新相关试卷Traffic at a Glance
一、字符串的排列
全排列在笔试面试中很热门,因为它难度适中,既可以考察递归实现,又能进一步考察非递归的实现,便于区分出考生的水平。所以在百度和迅雷的校园招聘以及程序员和软件设计师的考试中都考到了,因此本文对全排列作下总结帮助大家更好的学习和理解。对本文有任何补充之处,欢迎大家指出。
首先来看看题目是如何要求的(百度迅雷校招笔试题)。
一、字符串的排列
用C++写一个函数, 如 Foo(const char *str), 打印出 str 的全排列,
如 abc 的全排列: abc, acb, bca, dac, cab, cba
一、全排列的递归实现
为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。首先考虑213和321这二个数是如何得出的。显然这二个都是123中的1与后面两数交换得到的。然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。找到这个规律后,递归的代码就很容易写出来了:
123456789101112131415161718192021222324252627#include&iostream& &
using namespace std; &
#include&assert.h& &
void Permutation(char* pStr, char* pBegin) &
& & assert(pStr && pBegin); &
& & if(*pBegin == '\0') &
& & & & printf(&%s\n&,pStr); &
& & else &
& & { &
& & & & for(char* pCh = pBegin; *pCh != '\0'; pCh++) &
& & & & { &
& & & & & & swap(*pBegin,*pCh); &
& & & & & & Permutation(pStr, pBegin+1); &
& & & & & & swap(*pBegin,*pCh); &
& & & & } &
& & } &
int main(void) &
& & char str[] = &abc&; &
& & Permutation(str,str); &
& & return 0; &
另外一种写法:
12345678910111213141516171819202122232425262728//k表示当前选取到第几个数,m表示共有多少个数
#include&iostream& &
using namespace std; &
#include&assert.h& &
void Permutation(char* pStr, char* pBegin) &
& & assert(pStr && pBegin); &
& & if(*pBegin == '\0') &
& & & & printf(&%s\n&,pStr); &
& & else &
& & { &
& & & & for(char* pCh = pBegin; *pCh != '\0'; pCh++) &
& & & & { &
& & & & & & swap(*pBegin,*pCh); &
& & & & & & Permutation(pStr, pBegin+1); &
& & & & & & swap(*pBegin,*pCh); &
& & & & } &
& & } &
int main(void) &
& & char str[] = &abc&; &
& & Permutation(str,str); &
& & return 0; &
如果字符串中有重复字符的话,上面的那个方法肯定不会符合要求的,因此现在要想办法来去掉重复的数列。
二、去掉重复的全排列的递归实现
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。下面给出完整代码:
1234567891011121314151617181920212223242526272829303132333435363738394041424344#include&iostream& &
using namespace std; &
#include&assert.h& &
//在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等 &
bool IsSwap(char* pBegin , char* pEnd) &
& & char *p; &
& & for(p = pBegin ; p & pEnd ; p++) &
& & { &
& & & & if(*p == *pEnd) &
& & & & & & return false; &
& & } &
& & return true; &
void Permutation(char* pStr , char *pBegin) &
& & assert(pStr); &
& & if(*pBegin == '\0') &
& & { &
& & & & static int num = 1; &//局部静态变量,用来统计全排列的个数 &
& & & & printf(&第%d个排列\t%s\n&,num++,pStr); &
& & } &
& & else &
& & { &
& & & & for(char *pCh = pBegin; *pCh != '\0'; pCh++) & //第pBegin个数分别与它后面的数字交换就能得到新的排列 & &
& & & & { &
& & & & & & if(IsSwap(pBegin , pCh)) &
& & & & & & { &
& & & & & & & & swap(*pBegin , *pCh); &
& & & & & & & & Permutation(pStr , pBegin + 1); &
& & & & & & & & swap(*pBegin , *pCh); &
& & & & & & } &
& & & & } &
& & } &
int main(void) &
& & char str[] = &baa&; &
& & Permutation(str , str); &
& & return 0; &
OK,到现在我们已经能熟练写出递归的方法了,并且考虑了字符串中的重复数据可能引发的重复数列问题。那么如何使用非递归的方法来得到全排列了?
三、全排列的非递归实现
要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如&1234&的下一个排列就是&1243&。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。
如何计算字符串的下一个排列了?来考虑&926520&这个字符串,我们从后向前找第一双相邻的递增数字,&20&、&52&都是非递增的,&26 &即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到&956220&,然后再将替换点后的字符串&6220&颠倒即得到&950226&。
对于像“4321”这种已经是最“大”的排列,采用STL中的处理方法,将字符串整个颠倒得到最“小”的排列&1234&并返回false。
这样,只要一个循环再加上计算字符串下一个排列的函数就可以轻松的实现非递归的全排列算法。按上面思路并参考STL中的实现源码,不难写成一份质量较高的代码。值得注意的是在循环前要对字符串排序下,可以自己写快速排序的代码(请参阅《白话经典算法之六 快速排序 快速搞定》),也可以直接使用VC库中的快速排序函数(请参阅《使用VC库函数中的快速排序函数》)。下面列出完整代码:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include&iostream& &
#include&algorithm& &
#include&cstring& &
using namespace std; &
#include&assert.h& &
//反转区间 &
void Reverse(char* pBegin , char* pEnd) &
& & while(pBegin & pEnd) &
& & & & swap(*pBegin++ , *pEnd--); &
//下一个排列 &
bool Next_permutation(char a[]) &
& & assert(a); &
& & char *p , *q , *pFind; &
& & char *pEnd = a + strlen(a) - 1; &
& & if(a == pEnd) &
& & & & return false; &
& & p = pEnd; &
& & while(p != a) &
& & { &
& & & & q = p; &
& & & & p--; &
& & & & if(*p & *q) &//找降序的相邻2数,前一个数即替换数 & &
& & & & { &
& & & & & & &//从后向前找比替换点大的第一个数 &
& & & & & & pFind = pEnd; &
& & & & & & while(*pFind & *p) &
& & & & & & & & --pFind; &
& & & & & & swap(*p , *pFind); &
& & & & & & //替换点后的数全部反转 &
& & & & & & Reverse(q , pEnd); &
& & & & & & return true; &
& & & & } &
& & } &
& & Reverse(a , pEnd); & //如果没有下一个排列,全部反转后返回false & &
& & return false; &
int cmp(const void *a,const void *b) &
& & return int(*(char *)a - *(char *)b); &
int main(void) &
& & char str[] = &bac&; &
& & int num = 1; &
& & qsort(str , strlen(str),sizeof(char),cmp); &
& & { &
& & & & printf(&第%d个排列\t%s\n&,num++,str); &
& & }while(Next_permutation(str)); &
& & return 0; &
至此我们已经运用了递归与非递归的方法解决了全排列问题,总结一下就是:
1、全排列就是从第一个数字起每个数分别与它后面的数字交换。
2、去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
3、全排列的非递归就是由后向前找替换数和替换点,然后由后向前找第一个比替换数大的数与替换数交换,最后颠倒替换点后的所有数据。
二、字符串的组合
题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
上面我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。
假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445#include&iostream& &
#include&vector& &
#include&cstring& &
using namespace std; &
#include&assert.h& &
void Combination(char *string ,int number,vector&char& &result); &
void Combination(char *string) &
& & assert(string != NULL); &
& & vector&char& result; &
& & int i , length = strlen(string); &
& & for(i = 1 ; i &= length ; ++i) &
& & & & Combination(string , i ,result); &
void Combination(char *string ,int number , vector&char& &result) &
& & assert(string != NULL); &
& & if(number == 0) &
& & { &
& & & & static int num = 1; &
& & & & printf(&第%d个组合\t&,num++); &
& & & & vector&char&::iterator iter = result.begin(); &
& & & & for( ; iter != result.end() ; ++iter) &
& & & & & & printf(&%c&,*iter); &
& & & & printf(&\n&); &
& & & & return ; &
& & } &
& & if(*string == '\0') &
& & & & return ; &
& & result.push_back(*string); &
& & Combination(string + 1 , number - 1 , result); &
& & result.pop_back(); &
& & Combination(string + 1 , number , result); &
int main(void) &
& & char str[] = &abc&; &
& & Combination(str); &
& & return 0; &
由于组合可以是1个字符的组合,2个字符的字符……一直到n个字符的组合,因此在函数void Combination(char* string),我们需要一个for循环。另外,我们用一个vector来存放选择放进组合里的字符。
方法二:用位运算来实现求组合
1234567891011121314151617181920212223242526272829303132#include&iostream& &
using namespace std; &
int a[] = {1,3,5,4,6}; &
char str[] = &abcde&; &
void print_subset(int n , int s) &
& & printf(&{&); &
& & for(int i = 0 ; i & n ; ++i) &
& & { &
& & & & if( s&(1&&i) ) & & & & // 判断s的二进制中哪些位为1,即代表取某一位 &
& & & & & & printf(&%c &,str[i]); & //或者a[i] &
& & } &
& & printf(&}\n&); &
void subset(int n) &
& & for(int i= 0 ; i & (1&&n) ; ++i) &
& & { &
& & & & print_subset(n,i); &
& & } &
int main(void) &
& & subset(5); &
& & return 0; &
字符串全排列扩展—-八皇后问题
题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。
这就是有名的八皇后问题。解决这个问题通常需要用递归,而递归对编程能力的要求比较高。因此有不少面试官青睐这个题目,用来考察应聘者的分析复杂问题的能力以及编程的能力。
由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把ColumnIndex的八个数字分别用0-7初始化,接下来我们要做的事情就是对数组ColumnIndex做全排列。由于我们是用不同的数字初始化数组中的数字,因此任意两个皇后肯定不同列。我们只需要判断得到的每一个排列对应的八个皇后是不是在同一对角斜线上,也就是数组的两个下标i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。
关于排列的详细讨论,详见上面的讲解。
接下来就是写代码了。思路想清楚之后,编码并不是很难的事情。下面是一段参考代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263#include&iostream& &
using namespace std; &
int g_number = 0; &
void Permutation(int * , int &, int ); &
void Print(int * , int ); &
void EightQueen( ) &
& & const int queens = 8; &
& & int ColumnIndex[queens]; &
& & for(int i = 0 ; i & queens ; ++i) &
& & & & ColumnIndex[i] = i; & &//初始化 &
& & Permutation(ColumnIndex , queens , 0); &
bool Check(int ColumnIndex[] , int length) &
& & int i,j; &
& & for(i = 0 ; i & length; ++i) &
& & { &
& & & & for(j = i + 1 ; j & length; ++j) &
& & & & { &
& & & & & & if( i - j == ColumnIndex[i] - ColumnIndex[j] || j - i == ColumnIndex[i] - ColumnIndex[j]) & //在正、副对角线上 &
& & & & & & & & return false; &
& & & & } &
& & } &
& & return true; &
void Permutation(int ColumnIndex[] , int length , int index) &
& & if(index == length) &
& & { &
& & & & if( Check(ColumnIndex , length) ) & //检测棋盘当前的状态是否合法 &
& & & & { &
& & & & & & ++g_number; &
& & & & & & Print(ColumnIndex , length); &
& & & & } &
& & } &
& & else &
& & { &
& & & & for(int i = index ; i & length; ++i) & //全排列 &
& & & & { &
& & & & & & swap(ColumnIndex[index] , ColumnIndex[i]); &
& & & & & & Permutation(ColumnIndex , length , index + 1); &
& & & & & & swap(ColumnIndex[index] , ColumnIndex[i]); &
& & & & } &
& & } &
void Print(int ColumnIndex[] , int length) &
& & printf(&%d\n&,g_number); &
& & for(int i = 0 ; i & length; ++i) &
& & & & printf(&%d &,ColumnIndex[i]); &
& & printf(&\n&); &
int main(void) &
& & EightQueen(); &
& & return 0; &
题目:输入两个整数n和m,从数列1,2,3…n中随意取几个数,使其和等于m,要求列出所有的组合。
1234567891011121314151617181920212223242526272829303132#include &iostream& &
#include &list& &
using namespace std; &
list&int& list1; &
void find_factor(int sum,int n) &
& & //递归出口 &
& & if(n&=0||sum&=0) &
& & & & return; &
& & //输出找到的数 &
& & if(sum==n) &
& & { &
& & & & list1.reverse(); &
& & & & for(list&int&::iterator iter=list1.begin();iter!=list1.end();iter++) &
& & & & & & cout&&*iter&&&+&; &
& & & & cout&&n&&endl; &
& & & & list1.reverse(); &
& & } &
& & list1.push_front(n); &
& & find_factor(sum-n,n-1);//n放在里面 &
& & list1.pop_front(); &
& & find_factor(sum,n-1);//n不放在里面 &
int main(void) &
& & int sum,n; &
& & cin&&sum&&n; &
& & cout&&&所有可能的序列,如下:&&&endl; &
& & find_factor(sum,n); &
& & return 0; &
c++ static的作用,以及static对象在类和函数中区别
static对象如果出现在类中,那么该对象即使从未被使用到,它也会被构造以及析构。而函数中的static对象,如果该函数从未被调用,这个对象也就绝不会诞生,但是在函数每次被调用时检查对象是否需要诞生。
下面详细说说static的功能以及它的来龙去脉:
static作为编程语言里面一种重要的数据类型,它的地位在面试的过程里也是相当的高。
为什么要引入static
函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现?最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。
什么时候用static
需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
static的内部机制
静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有定义;三是的main()函数前的全局数据声明和定义处。
静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态
数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。
static的优势
可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。
应用格式(C++)
引用静态数据成员时,采用如下格式:
&类名&::&静态成员名&
如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。
(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。
(2)不能将静态成员函数定义为虚函数。(注意:如果在static函数加上virtual关键字就会报出这样子的错误error: Semantic Issue: ‘virtual’ can only appear on non-static member functions,大家懂了吧!
(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地址是指向其数据类型的指针,函数地址类型是一个“nonmember”。
(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于函数身上。
(5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。
(6)静态数据成员在&定义或说明&时前面加关键字static。
(7)静态数据成员是静态存储的,所以必须对它进行初始化。
(8)静态成员初始化与一般数据成员初始化不同:
初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
初始化时不加该成员的访问权限控制符private,public等;
初始化时使用作用域运算符来标明它所属类;
所以我们得出静态数据成员初始化的格式:
&数据类型&&类名&::&静态数据成员名&=&值&
(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。在各通信公司的笔试面试中经常出现的考题就是static的作用及功能。
(1)面向对象的static关键字
  1、静态数据成员
在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。
//Example 1
#include &iostream.h&
class Myclass
Myclass(int a,int b,int c);
void GetSum();
int a,b,c;
static int S//声明静态数据成员
int Myclass::Sum=0;//定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{ this-&a=a;
this-&b=b;
this-&c=c;
Sum+=a+b+c;}
void Myclass::GetSum()
{ cout&&“Sum=”&&Sum&&
void main()
{ Myclass M(1,2,3);
M.GetSum();
Myclass N(4,5,6);
N.GetSum();
M.GetSum();}
可以看出,静态数据成员有以下特点:
对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;
静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它.
类的静态数据成员有两种访问形式:
&类对象名&.&静态数据成员名& 或 &类类型名&::&静态数据成员名&
如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;
同全局变量相比,使用静态数据成员有两个优势:
静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;
与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数fn()实际上是this-&fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。
//Example 2
#include &iostream.h&
class Myclass
Myclass(int a,int b,int c);
static void GetSum();/声明静态成员函数
int a,b,c;
static int S//声明静态数据成员
int Myclass::Sum=0;//定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{ this-&a=a;
this-&b=b;
this-&c=c;
Sum+=a+b+c; //非静态成员函数可以访问静态数据成员
void Myclass::GetSum() //静态成员函数的实现
// cout&&a&& //错误代码,a是非静态数据成员
cout&&“Sum=”&&Sum&&
void main()
{ Myclass M(1,2,3);
M.GetSum();
Myclass N(4,5,6);
N.GetSum();
Myclass::GetSum();
关于静态成员函数,可以总结为以下几点:
出现在类体外的函数定义不能指定关键字static;
静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
静态成员函数不能访问非静态成员函数和非静态数据成员;
由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
调用静态成员函数,可以用成员访问操作符(.)和(-&)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
&类名&::&静态成员函数名&(&参数表&)
调用类的静态成员函数。
static静态变量声明符。在声明它的程序块,子程序块或函数内部有效,值保持,在整个程序期间分配存储器空间,默认值0。
是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性
(2)面向过程的static关键字:功能:隐藏作用、值保持。
隐藏作用。当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。如果加了static,就会对其它源文件隐藏。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。
保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。
默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\ 0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。
总之,首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。
另外,记住c++的一个哲学基础:你不应该为你并不使用的东西付出任何代价。

我要回帖

更多关于 int float double 的文章

 

随机推荐