对课程前面40课的详细回顾分析(一)
0、
- int main()
- {
- // ① Array t(3,3); //普通模式
- // ② Array *t=new Array(3,3); //指针方式
- // cout<<t->a<<endl;
- //③ Array t=Array(3,3); //临时对象
- //cout<<t.a<<endl;
- int b=3;
- int *p=&b;
- int *a=new int(b); //在堆空间申请一个int 里面存的值为b
- cout<<p<<endl<<a<<endl;
- return 0;
- }
1、在最初语言规划的阶段,C语言的出现纯粹是为了编写unix操作系统;造成了C语言没有太多深思熟虑的过程,遗留了太多低级语言的特征; 进而造成了软件的可维护性和可重用性差。
c++中的register关键字对于C语言只是一个兼容性问题,在c++中遇到register关键字的时候会自动忽略掉;在c++中的任意标识符都必须显式的指明类型 。
2、
C语言中的const修饰的变量(无论是全局变量还是局部变量都只是只读的,本质上还是变量,不是真正意义上的常量;只在编译期间有用,在运行时无用,所以我们可以骗过编译器对一个const修饰的变量进行修改)
骗过编译器修改const修饰变量的的方法:
- int main()
- {
- const int a=5;
- int *p=(int *)&a;
- *p=4;
- printf("a=%d *p=%d ",a,*p);
- return 0;
- }
但是在c++中能够定义真正意义上的常量,是不能够修改的。
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。
- int main()
- {
- int a=5;
- int *p1=&a;
- int &b=a; //引用
- b=4;
- int *p2=&b;
- printf("a=%d ",a);
- printf("%p %p ",*p1,*p2);
- return 0;
- }
int * p
(1)const int *p
(2)int const *p
(3)int * const p
(4)const int *const p
引用和指针的区别和联系:
★ 相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
★ 区别:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
引用“从一而终” ^_^
4. 引用没有 const,指针有 const,const 的指针不可变;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,
但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
7. 指针和引用的自增(++)运算意义不一样;
3、c++中可以使用const常量代替宏常数定义;同样我们可以使用内联函数来替代宏代码片段。内联函数在声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。c++编译器可以将一个函数内联编译,所谓的内联编译就是编译器直接将函数体插入到函数调用的地方,类似于宏定义替换;内联函数省去了普通函数调用时的额外开销(压栈、跳转、返回);但是inline只是一种请求,c++编译器对于函数的内联请求不一定都会满足。
4、c++可以在函数声明时为参数提供一个默认值,当函数调用时没有提供参数时候则使用默认值;尤其需要指出的一点是参数的默认值必须在函数声明中指定;当函数声明和函数定义中都有一个默认值时候则选用函数声明中的默认值,同时可以在函数参数中使用占位参数,占位参数只有函数参数类型声明,而没有参数名。
5、c++中int function()和int function(void)没有区别,都表示无参数接收,返回值为int的函数;但是在C语言中前者表示可以接收任意参数,后者才表示不接受参数。
6、重载函数本质上是一个个相互独立的不同的函数,函数重载是由函数名和参数列表决定的,返回值不能作为判断依据。
extern关键字可以实现C语言和c++的相互调用。函数重载在c++中才可以,在C语言中不行。
7、new关键字
8、
const引用其实就是const int * const p,生成一个新的只读变量。
const int &a=b;也是一个只读变量
volatile const int &a;也是一个只读变量
const int &a=5;//常量
9、c++中的强制类型转换
(1)dynamic_cast操作符:用于基类和派生类之间的类指针或者类引用的转换,基类中必须要有虚函数。
用法:
classB
{
public
:
int
m_iNum;
virtual
void
foo();
};
classD:publicB
{
public
:
char
* m_szName[100];
};
void
func(B* pb)
{
D* pd1=
static_cast
<D*>(pb);
D* pd2=
dynamic_cast
<D*>(pb);
}
classA
{
public
:
intm_iNum;
virtual
void
f(){}
};
class
B:
public
A
{
};
class
D:
public
A
{
};
void
foo()
{
B*pb=newB;
pb->m_iNum=100;
//D*pd1=static_cast<D*>(pb);//compile error
D*pd2=
dynamic_cast
<D*>(pb);
//pd2isNULL
delete
pb;
}
(2)const_cast操作符:用于去除变量的const只读属性,强制转换的目标类型必须是指针或者引用。
- int main()
- {
- const int a=3;
- int *p=const_cast<int *>(&a);
- *p=5;
- cout<<*p<<endl; //*p=5
- return 0;
- }
(3)static_cast操作符:可以把它完全当作C语言中的暴力强制类型转换,该操作符用于非多态类型的转换,任何标准转换都可以使用,即static_cast可以把int转换为double,但不能把两个不相关的类对象进行转换,比如类A不能转换为一个不相关的类B类型,但是 对于两个相关的类转换其类对象是可以的。static_cast本质上是传统c语言强制转换的替代品。
(4)reinterpret_cast操作符:用于指针类型间的类型转换 ,用于整数和指针之间的类型转换。
代码示例:
- int main()
- {
- int a=3;
- int *p=&a;
- cout<<p<<endl;
- double b=3.90;
- double *p1=&b;
- cout<<p1<<endl;
- p1=reinterpret_cast<double *>(p);
- // p1=(double *)p; //c语言的转换方法
- cout<<p1<<endl;
- return 0;
- }
10、深究引用(引用和指针的关系深究)
对于引用变量的内部实现,可以得出如下结论:
引用变量:
1)引用的内部实现为相当于一个指针常量 int *const p ,与指针的实现方式类似;
2)引用变量内存单元保存的指向变量地址(初始化时赋值),与指针不同地方时,引用变量在定义时必须初始化,而且使用过程中,引用变量保存的内存单元地址值是不能改变的(这一点通过编译器来实现保证);
3)引用也可以进行取地址操作,但是取地址操作返回的不是引用变量所在的内存单元地址,而是被引用变量本身所在的内存单元地址;(对引用变量的取地址操作相当于取内容操作,如果要想取得引用变量的地址,应使用两次取地址符号,如:&(&a) )
4)引用的使用,在源代码级相当于普通的变量一样使用,但在函数参数传递引用变量时,内部传递的实际是变量的地址值(这种机制的实现是通过编译器(编译手段)来实现的)。
不能将引用简单理解为变量的代记符号,引用本身是通过指针实现,并且占用相应的内存空间。
参考博客:http://blog.csdn.net/thisispan/article/details/7456169
11、重载、重写和多态的区别?
c++中的多态性本质上是为了接口重用,体现在函数重写上;而函数重载只发生在一个类中,不像重写那样在基类和子类中,所以不算是多态性的体现。
重定义和重写虽然都发生在基类和派生类之间,但是重写是对基类的虚函数进行重写(函数名,参数列表都需要跟基类的一致),而重定义是对基类的非虚成员函数进行函数定义,
函数 的参数列表不用跟基类的保持一致。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12、类之间的基本关系:组合和继承。组合是has-a,整体和局部的关系;继承是is-a的关系,子类拥有父类的全部属性和方法。
13、一个类中可以存在多个重载的构造函数,构造函数的重载依靠C++的重载规则。
14、
15、析构函数和构造函数的一些问题:
注意一点:析构函数是在类对象释放时候才被调用的,对于其他的指针可以用delete删除。
析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
以C++语言为例:[1] 析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显示的析构函数。
1
2
3
4
5
6
7
8
9
|
class <类名> { public : ~<类名>(); }; <类名>::~<类名>() { //函数体 }; |
1
2
3
4
5
6
7
8
9
|
class T { public : ~T(); }; T::~T() { //函数体 }; |