C++的一些基础细节(备考用)

classnode

{

public:

node(){cout
<<"constructor node()"<<endl;}

~node(){cout<<"destructor ~node()"<<endl;}

};

classnn

{

public:

node x;

nn(){cout
<<"con nn()"<<endl;}

~nn(){cout<<"des ~nn()"<<endl;}

};

intmain()

{

nn a;



return0;

}

几年前的一份C++笔记。

看完了Bruce Eckel的Thing in C++(Volume 1),实践比较少,感觉还是半懂不懂,马上就要【面向对象程序设计】的考试了。考的是C++的东西,做了几份C++的卷子,感觉好多细节的东西还是很不确 定,不敢下手。于是今天把老师的课件翻了出来,整理了一下,做了个小结。虽然感觉很乱,但是对于我自己来说,还是能看懂,很多东西都很显而易见的也写了, 无论怎样,只是为了考试^_^


extern int xx 这是一个声明,而不是定义


在class temp中只定义一个static int b;

1sizeof(temp)=1这是为什么?

static 变量是这个类共享的,变量是放在全局变量区,不是堆栈里,因此sizeof出来不算在这个static int的大小;是这样的吗??


枚举类型的变量只能进行赋值运算


指针int p,后不能直接进行p = 12这样的赋值,因为指针p没有申请内存


如何解释以下程序?1intmain()

2{

3inta;

4

5a=(int)"string";

6cout<<a<<endl;

7cout<<a<<endl;

8return0;

9}a指向一个string常量的,强制转换为int,因此a还是"string"常量的首地址,*a应该是取前面几位的值


析构函数的调用不一定要大括号

classnode

{

public:

node(){cout<<"node()"<<endl;}

~node(){cout<<"~node()"<<endl;}

};

intmain()

{

if(1)

node n;

cout<<"out of if"<<endl;



return0;

}输出为

node()

~node()

out of if

另外,一个大括号就是一个scope,不管有没有if,while等语句


if(!cin)

相当于if(cin.fail())

!的运算符在这里被重载了


函数中的static变量在结束main()的时候才释放,但是在全局变量之前


全局变量区:全局变量,静态全局变量,静态本地变量

stack:本地变量

heap:申请的变量,例如,new,malloc

要注意的是new和malloc不能混用


class 中的public表示所有的object都能访问

private只能让类声明的函数和friend函数访问

protected可以子类访问,也可以被friend函数访问


无论是数组还是指针,传到函数中都变为指针


只有在没有构造函数的情况下,编译器才自动分配一个构造函数,否则,只要

编译器看到一个构造函数,就不会生成一个构造函数。

另外,编译器自动生成的构造函数是没有参数的。


根据函数的参数的个数或者类型的不同可以重载函数。

如果只是返回值不同,则不能重载。


缺省参数的函数。缺省值只能从后往前写。

也就是说int f(int i , int j = 0);是可以的。

但是int f(int i = 0 ; int j);是不对的。


一个class中如果有const 常量,声明的时候不能初始化,否则编译器报错

但是如果是static const int a = 0就可以

class中的const int a可以在构造函数中初始化,注意只能在初始化列表中,不能在函数体中赋值

其他的地方定义const 则需要初始化

如果是extern const int a ;就可以不做初始化


内联函数应该放在.h的文件中,因为它是一个声明

另外在class中定义的函数是内联的


1constinta=10;

2inty=a;

是可以的


1constintsize=10;

2inta[size];

是正确的。

但是

1intx=10;

2constintsize=x;

3doubleclassAverage[size];会报错(为什么?)


1constintsize[3]={2,3,4};

2inta[size[0]];

是错的。

也不能这样定义

1structS {inti, j; };

2constS s[]={ {1,2}, {3,4} };

3doubled[s[1].j];


1charconstp="abc";表示p指向的地址是常量,指向的地址不能改变,但是指向的内容可以变

1charconstp="abc";表示p指向的内容是常量,不能改变,但是指向的地址可以改变


1intip;

2constintcip ;//指针可以不初始化

3constintt=3;

4inti;

5ip=&i ;

6ip=&t ;//错误,非常量指针不能指向常量

7cip=&i;

8cip=&t;

9ip=54;

10cip=54;//错误


1chars="hello , world";

是可以的,因为编译器自动转化为

1constchars="hello,world";因此不能再改变s的值了。 但是s指向的地址是可以改变的


voidf(constintx){}

voidg(intx){}

inta=0;

constintb=0;

f(a);

g(b);
都是可以的


如果返回值是const,可以赋给non-const,如果不是const 也可以赋给const


如果一个对象定义的时候是const,不能修改这个对象的值


intnode::f()const

函数中不能修改成员变量

也不能调用非常量函数



intnode::f(){}

intnode::g()const{f();}是错的。


不能这样定义

classnode

{

private:

constintsize;

inta[size];

};
可以把const int 改为static const int

或者用enum来做


引用不能改变

inty , z;

int&x=y;

&x=z;//错误,引用不能改变


intf(int&){}不能调用f(t * 3);


不能这样定义

int&p;但是可以这样

int&p;


引用变量的构造函数中也只能初始化,而不能赋值


如果函数的返回值是const的,就不能做左值


在node a = b;或者node a(b);拷贝构造调用。

当函数返回一个对象的时候,拷贝构造被调用

node f()

{

node x;

returnx;

}
在函数的参数中有对象的时候,调用拷贝构造

intf(node x)

{

return1;

}
但是如果参数的引用,拷贝构造不被调用

intf(constnode&)

{

return1;

}



静态函数只能对静态变量进行操作



函数中的静态变量只能被初始化一次



static 成员变量在同类的对象中都可见



不能用this来取值



namesapce

可以用using nm::f();

voidmain() {

usingMyLib::foo;

usingMyLib::Cat;

foo();

Cat c;

c.Meow();

}




namespacemy1

{

intf(){cout<<"my1::f()"<<endl;return0;}

intg(){cout<<"my1::g()"<<endl;return0;}

}

namespacemy2

{

intf(){cout<<"my2::f()"<<endl;return0;}

inth(){cout<<"my2::h()"<<endl;return0;}

}

intmain()

{

usingnamespacemy1;

usingnamespacemy2;

f();

g();

h();



return0;

}
编译器报错,因为编译器不知道应该调用哪一个f(),

如果不调用f(),编译器就不会报错了。

但是如果将f()变为my1::f()就可以了

注意namespace后面没有";"



【运算符重载】



可以重载的运算符:

+ - * / % ^ & | ~

= < > += -= = /= %=

^= &= |= << >> >>= <<= ==

!= <= >= ! && || ++ --

, ->
-> () []

operator new operator delete

operator new[] operator delete[]



不能被重载的运算符

. .:: ?:

sizeof typeid

static_cast dynamic_cast

const_cast renterpret_cast

另外不能重载不存在的运算符,例如
*



运算符重载后的优先级不变

所接受的参数的个数也不变



重载为成员函数,可以省略第一个参数,但是

z = x + y;//可以

z = x + 3;//可以

z = 3 + y;//不可以

因为只看第一个参数

但是如果重载为全局函数,以上三个表达式都正确



必须是member function:

= () [] -> ->*

还有一元的运算符必须是member function

所有的二元运算符可以是non-member fuction



函数原型:

+ - * / % ^ & | ~

const T operatorX(const T& l, const T& r);

! && || < <= == >= >

bool operatorX(const T& l, const T& r);

[]

T& T::operator;



++ -- 运算符的重载

constInteger&operator++();//++a

constIntegeroperator++(int);//a++

constInteger&operator--();//--a

constIntegeroperator--(int);//a--在后缀++重载的时候,应该先将原来的对象保存下来用来返回

在调用a++的时候,实际上调用的是a.operator++(0)

//前缀比后缀更加高效



关系运算符的重载

booloperator==(constInteger&rhs )const;

booloperator!=(constInteger&rhs )const;

booloperator<(constInteger&rhs )const;

booloperator>(constInteger&rhs )const;

booloperator<=(constInteger&rhs )const;

booloperator>=(constInteger&rhs )const;



【继承】



输出:

constructor node()

con nn()

des ~nn()

destructor ~node()



在构造函数调用的时候,总是基类先被调用

而析构函数的调用与构造函数的调用是反过来的



如果在子类定义了一个函数与父类的名字相同的话,父类中所有同名的函数被屏蔽



继承后

构造函数,析构函数,operator=,private不能被继承

子类不能访问private的变量,但是可以访问protected的变量



在继承中

class base:derived默认为private继承



class derived:public base

base的public在derived是public,protected在derived是protected,private在derived中被 隐藏

class derived:protected base

base的public在derived是protected,protected在derived是protected,private在 derived中被隐藏

class derived:private base

base的public在derived是private,protected在derived是private,private在derived中被隐 藏



upcasting

base &b = pete;//pete是子类,base是父类

b->f();

调用的是父类的f();

但是如果父类的f()是virtual的话,调用的是子类的f()



voidfunc(Ellipse&elly) {

elly.render();

}

Circle circ(60F);

func(circ);
调用的是Circle::render();

但是如果

voidfunc(Ellipse elly) {

elly.render();

}

Circle circ(60F);

func(circ);
调用的是Ellipse::render();



析构函数也可以virtual,作用与前面一样



base*p=newderived;

delete p;
如果析构函数是virtual的,调用的是derived的析构函数,同时也会调用base的

否则调用的只是base的



overriding

可以这样定义:

在base中:virtual base& f();

在derived中:virtual base& f();

但是不能这样定义

在base中:virtual base f();

在derived中:derived f();



当override一个函数的时候,最好重载所有的函数



在构造函数中调用的virtual function是本身的f()



template<classT>

voidswap(T&a , T&b)

{

T temp;

temp
=a;

a
=b;

b
=temp ;

}
不能这样调用

inta;

doubleb;

swap(a,b);



template<classT>

voidfoo(){/**/}

foo
<int>//此处的T为int



类的模版

template

class node.....

创建对象的时候,可以

node...

如果函数不是内联的,在函数的定义的时候,前面要加上

template



template

template>注意后面是有空格的

</vector\



也可以是变量

template

可有带有缺省参数

template



模版可以用在继承上

template

class Derived : public List{...};



模版应该放在.h的文件中



【异常】



try{}catch(){}catch{}



catch所有的异常

catch(...);



关于new的异常处理

voidfunc() {

try{

while(1)

{

char*p=newchar[10000];

}

}
catch(bad_alloc&e)

{

}

}




还有一些stream的东西还没看。

另外,template和exception的貌似不怎么考,因此比较少T_T 原文链接: https://www.cnblogs.com/vivyli/archive/2010/02/05/1664061.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/7957

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月6日 下午6:37
下一篇 2023年2月6日 下午6:38

相关推荐