1.在C++ 程序中调用被C 编译器编译后的函数,为何要加extern “C”?html
答:C++语言支持函数重载,C 语言不支持函数重载。函数被C++编译后在库中的名字与C 语言的不一样。假设某个函数的原型为: void foo(int x, int y);c++
该函数被C 编译器编译后在库中的名字为_foo , 而C++ 编译器则会产生像_foo_int_int 之类的名字。编程
C++提供了C 链接交换指定符号extern“C”来解决名字匹配问题。数组
http://yjbys.com/bishi/timu/598258.html安全
2.char * strcpy(char * strDest,const char * strSrc);ide
1
2
3
4
5
6
7
8
9
|
⒈
strcpy
的实现代码
char
*
strcpy
(
char
* strDest,
const
char
* strSrc)
{
if
((NULL==strDest) || (NULL==strSrc))
//[1]
throw
"Invalid argument(s)"
;
//[2]
char
* strDestCopy = strDest;
//[3]
while
((*strDestCopy++=*strSrc++)!=
'\0'
);
//[4]
return
strDest;
}
|
C++多态性是经过虚函数来实现的,虚函数容许子类从新定义成员函数,而子类从新定义父类的作法称为覆盖(override),或者称为重写。(这里我以为要补充,重写的话能够有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算做是体现了C++多态性)而重载则是容许有多个同名的函数,而这些函数的参数列表不一样,容许参数个数不一样,参数类型不一样,或者二者都不一样。编译器会根据这些函数的不一样列表,将同名的函数的名称作修饰,从而生成一些不一样名称的预处理函数,来实现同名函数调用时的重载问题。但这并无体现多态性。模块化
多态与非多态的实质区别就是函数地址是早绑定仍是晚绑定。若是函数的调用,在编译器编译期间就能够肯定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而若是函数调用的地址不能在编译器期间肯定,须要在运行时才肯定,这就属于晚绑定。函数
那么多态的做用是什么呢,封装可使得代码模块化,继承能够扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的到底是那个类的对象,函数都可以经过同一个接口调用到适应各自对象的实现方法。url
最多见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,能够根据指向的子类的不一样而实现不一样的方法。若是没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数自己,而没法调用到子类中被重写过的函数。由于没有多态性,函数调用的地址将是必定的,而固定的地址将始终调用到同一个函数,这就没法实现一个接口,多种方法的目的了。spa
虚函数理解:
对于虚函数调用来讲,每个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。因此在程序中,无论你的对象类型如何转换,但该对象内部的虚表指针是固定的,因此呢,才能实现动态的对象函数调用,这就是C++多态性实现的原理。
总结(基类有虚函数):
一、 每个类都有虚表。
二、 虚表能够继承,若是子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。若是基类3个虚函数,那么基类的虚表中就有三项(虚函数地址),派生类也会有虚表,至少有三项,若是重写了相应的虚函数,那么虚表中的地址就会改变,指向自身的虚函数实现。若是派生类有本身的虚函数,那么虚表中就会添加该项。
三、 派生类的虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。
http://blog.csdn.net/youngchang06hpu/article/details/8715011
4. 引用与指针
http://blog.csdn.net/youngchang06hpu/article/details/8715011
参考:《c和指针》
1 引用是C++中的概念,C中没有引用,而只有&操做,即取地址符,其必须做用于一个左值。
2 引用是变量的一个别名,即创建引用并不会致使新内存的分配,引用在初始化时必须存在一个对应的被引用的内存对象,且此引用关系创建后,引用不能再被改变,而所引用的变量是能够改变的。
3 引用在参数传递中使用,下降了传值传递的消耗。若是引用做为函数的返回值,那么函数能够做为一个左值来使用。这一点在C++的流操做部分很常见。
int a[5]={1,2,3,4,5};
int *p1=(int*)(&a+1);
int *p2=(int*)((int)a+1);
int *p3=(int*)(&a)+1;
// p3=p3+1;
printf("%x,%x,%x",p1[-1],*p2,p3[-1]);
执行结果为 5,2000000,1。对于结果5仍是比较纠结。看了一下网上的帖子和几本书,总结了一下。
首先说一下关于对数组名取地址:
关于对数组名取地址的问题,因为数组名是右值,原本&array 是不合法的,早期很多编译器就是指定&array 是非法的,但后来C89/C99认为数组符合对象的语义,对一个对象取地址是合理的,所以,从维护对象的完整性出发,也容许&array 。只不过,&array 的意义并不是对一个数组名取地址,而是对一个数组对象取地址,也正由于如此,array 才跟&array 所表明的地址值同样,同时sizeof(array )应该跟sizeof(&array )同样,由于sizeof(&array )表明取一个数组对象的长度。
要注意到 array 和 &array 的类型是不一样的。array为一个指针,而&array是指向数组int [100]的指针。array 至关于 &array[0],而 &array 是一个指向 int[100] 的指针,类型是 int(*)[100]。
另外从步长的角度分析这个问题
执行以下语句:
printf("array=%p, array+1=%p/n", array, array+1);
printf("&array=%p, &array+1=%p/n", &array, &array+1);
结果为:
array=0012FDF0, array+1=0012FDF4 //+sizeof(int)
&array=0012FDF0, &array+1=0012FF80 //+sizeof(&array)
在《C专家编程》书中关于数组一章P203,有以下解释: 不管指针仍是数组,在连续的内存地址上移动时,编译器都必须计算每次前进的步长。 编译器自动把下标值调整到数组元素大小,对起始地址进行加法操做以前,编译器都会负责计算每次增长的步长,这就是为何指针类型老是有类型限制,每一个指针只能指向一种类型的缘由所在,由于编译器须要知道对指针进行解除引用操做时应该取几个字节,以及每一个小标的步长应取几个字节。 另外步长的自动调整还和上下语句相关: int *p3=(int*)(&a); p3=p3+1; 首先对P3指针变量赋初值,指向数组int [5]的指针,而后对指针进行加一的操做,其中P3定义为一个指向int类型的指针,所以最终P3的值等价P3+sizeof(int) int *p3=(int*)(&array+1); &array+1,步长为1,其中步长的长度和&array的类型匹配,即&array是指向数组int [100]的指针,因此&array+1等价为&array+sizeof(&array) 最终p1[-1]等价为*(P1-1),所以等价为第二个int [5]的数据首地址(并不存在第二个数组显然当前指针已经越界了,另外数组元素在内存中是连续存贮的)减去一个为sizeof(int)的步长,因此指向了第一个数组的最后1个元素。