1.操作符重载,总结一下,个人觉得只有三种情况:
情形a: 在类内部重载操作符
class base{
public:
base(int x){
a = x;
}
base & operator+(base &obj1);
void get_number(){
cout << a << endl;
}
private:
int a;
};
base & base::operator + (base &obj1){
this->a += obj1.a;
return *this;
}
int main(){
base b1(1);
base b2(2);
b1 + b2;
b1.get_number();
return 0;
}
情形2:在外部重载:
class base{
public:
base(int x){
a = x;
}
void get_number(){
cout << a << endl;
}
int a;
};
base & operator + (base &obj1,base &obj2){
obj1.a+= obj1.a;
return *(&obj1);
}
情形3:友元重载
class base{
public:
base(int x){
a = x;
}
void get_number(){
cout << a << endl;
}
friend base &operator+(base &obj1,base &obj2);
private:
int a;
};
base & operator + (base &obj1,base &obj2){
obj1.a+= obj1.a;
return *(&obj1);
}
2.c++让人眩晕的指针
1.int(**ptr)[10];//下面有讨论
2.int*(*ptr)[10];//如果写成int(*ptr)[10]大家都知道,ptr是一个指向有10个元素的素组每个元素是int型,
//那么类比,int*(*ptr)[10]中ptr也是指向含有10个元素的数组,但是数组中的每个元素是int *型的
3.int(*f[10])(int);//函数指针数组,f的每个元素都指向参数为int型,返回int值的函数
4.int *((*ptr)[10]);//和第二种情况一样
在弄清楚之前我们要知道下面的几个指针
int *ptr:这个指针指向的是一个int型对象,如果ptr++则跳到下一个int型对象的地址;
int (*ptr)[10]:这是一个一维数组指针,ptr++会跳过10个int型对象;
当数组名作为函数参数的时候,编译器自动将其转化成int *的变量;
#include<iostream>
#include<vector>
#include<list>
#include<fstream>
#include<string>
#include<set>
#include<map>
#include<algorithm>
#include<stack>
using namespace std;
#define size 10
int func(int ar[]){
cout << typeid(ar).name()<< endl;
return 0;
}
int main(){
int (*p)[10];
int arr[10];
for (int j = 0; j < size;j++){
arr[j] = rand() % 100;
}
p = &arr;//可以看到arr的类型为int [10],在&运算符后就变成int(*)[10]
cout << typeid(&arr).name() << endl;
int(**ptr)[10] = &p;
cout << *(**ptr+1) << endl;//ptr存放的是p变量的地址,*ptr(和p的值一样)就指向了含有10个元素的数组的地址,此时是行地址
//**ptr将行地址转换成列地址,**ptr+1就是数组中第一个元素的地址,*(**ptr+1)就是第一个元素的值
//如有不懂,参考我的另外一篇博客:http://blog.csdn.net/caoyan_12727/article/details/52549075
cout << *((int *)p+1) << endl;
func(arr);
return 0;
}
输出:
3.定义变长结构体
struct node{
int a;
int arr[0];//不为arr分配空间
};
int main(){
cout << sizeof(node) << endl;
struct node * ptr = (struct node *)malloc(20 * sizeof(char));//ptr指向20字节的空间
for (int i = 0; i < 5; i++){
*((int *)ptr + i) = rand() % 20;
cout << *((int *)ptr + i) << endl;
}
cout << ptr->a << endl;
return 0;
}
4.使用变长参数:
代码:
int sum(int num,...){
int sum=0;
va_list ap;
va_start(ap,num);
for (int i = 0; i < num; i++){
sum += va_arg(ap, int);
}
va_end(ap);
<span style="white-space:pre"> </span>return sum;
}
int main(){
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int re = sum(4,a,b,c,d);
cout << re << endl;//re正确输出10
return 0;
}
边长参数的实现依赖于下面5个宏:
1)typedef char * va_list;
2)_INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
3)VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
4)VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
5)VA_END宏,清空va_list可变参数列表:
#define va_end(ap) ( ap = (va_list)0 )
5.malloc(0)的特殊情况:
<pre name="code" class="cpp">int main(){
char* ptr = (char *)malloc(0 * sizeof(char));
if (NULL == ptr)printf("got a null pointer\n");
else printf("got a valid pointer\n");
printf("%p\n", ptr);
free(ptr);
cout << sizeof(ptr) << endl;
printf("0x%01x\n", *ptr);
bitset<8>bit(*ptr);
cout << "bit:"<<bit << endl;
cout << "*ptr:"<<*ptr << endl;
//另外测试:
char ch = 'a';
char *ptr1 = &ch;
bitset<8>bit1(*ptr1);
cout << bit1 << endl;
return 0;
}
输出:
这个目前没搞懂,希望高人指点!!!!!
6.指针和数组在函数调用的时候的传递
#include<iostream>
using namespace std;
void func(int a,char arr[],char *p){
cout<<"here!"<<endl;
}
int main(){
int a=10;
char s[]="aaaaaaaaaaaaaaaaaaaaaaaaa";
char *p="bbbbbbbbbb";
func(a,s,p);
return 0;
}
汇编码:
0804872a <main>:
804872a: 8d 4c 24 04 lea 0x4(%esp),%ecx
804872e: 83 e4 f0 and $0xfffffff0,%esp
8048731: ff 71 fc pushl -0x4(%ecx)
8048734: 55 push %ebp
8048735: 89 e5 mov %esp,%ebp
8048737: 51 push %ecx
8048738: 83 ec 34 sub $0x34,%esp
804873b: 65 a1 14 00 00 00 mov %gs:0x14,%eax
8048741: 89 45 f4 mov %eax,-0xc(%ebp)
8048744: 31 c0 xor %eax,%eax
8048746: c7 45 d0 0a 00 00 00 movl $0xa,-0x30(%ebp)
804874d: c7 45 da 61 61 61 61 movl $0x61616161,-0x26(%ebp)
8048754: c7 45 de 61 61 61 61 movl $0x61616161,-0x22(%ebp)
804875b: c7 45 e2 61 61 61 61 movl $0x61616161,-0x1e(%ebp)
8048762: c7 45 e6 61 61 61 61 movl $0x61616161,-0x1a(%ebp)
8048769: c7 45 ea 61 61 61 61 movl $0x61616161,-0x16(%ebp)
8048770: c7 45 ee 61 61 61 61 movl $0x61616161,-0x12(%ebp)
8048777: 66 c7 45 f2 61 00 movw $0x61,-0xe(%ebp)
804877d: c7 45 d4 a6 88 04 08 movl $0x80488a6,-0x2c(%ebp)
8048784: 83 ec 04 sub $0x4,%esp
8048787: ff 75 d4 pushl -0x2c(%ebp)
804878a: 8d 45 da lea -0x26(%ebp),%eax
804878d: 50 push %eax
804878e: ff 75 d0 pushl -0x30(%ebp)
8048791: e8 65 ff ff ff call 80486fb <_Z4funciPcS_>
8048796: 83 c4 10 add $0x10,%esp
8048799: b8 00 00 00 00 mov $0x0,%eax
804879e: 8b 55 f4 mov -0xc(%ebp),%edx
80487a1: 65 33 15 14 00 00 00 xor %gs:0x14,%edx
80487a8: 74 05 je 80487af <main+0x85>
80487aa: e8 11 fe ff ff call 80485c0 <__stack_chk_fail@plt>
80487af: 8b 4d fc mov -0x4(%ebp),%ecx
80487b2: c9 leave
80487b3: 8d 61 fc lea -0x4(%ecx),%esp
80487b6: c3 ret
我们可以看到:
(1)对于普通变量a是是将它的地址入栈
pushl -0x30(%ebp)
(2)对于数组,也是将它的地址入栈
804878a: 8d 45 da lea -0x26(%ebp),%eax
804878d: 50 push %eax
(3)对于指针变量:
8048787: ff 75 d4 pushl -0x2c(%ebp)
也是将它的地址入栈
在这里我们要注意两个串,一个是"aaaaaaaaa"和"bbbbbbbbbbbb",前者对数组进行赋值,后者是将其存放在.rodata段,而将其地址赋值给变量p;
7.内联函数与虚函数之间的关系
1.内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的。
2.我们之所以能看到一些象内联函数的虚函数,是因为某个函数是否是内联函数不是由我们说的算,而是由编译器决定的。我们只能向编译器建议,某个函数可以是内联函数(inline关键字),但是编译器有自己的判断法则。所以可能出现这样的情况:
2.1 我们用inline声明的函数却没有inline
2.2 我们没有用inline声明的函数却是inline
2.3 对于inline函数,编译器仍然将它编译成一个有地址的函数
所以,情况比较复杂,从high-level来看的话很难判断函数是否是inline的,如果从low-level来看的话就比较清晰,非内联函数遵从函数调用机制,在汇编中用call来调用。内联函数则没有这些。
class base{
public:
inline ~base(){
cout << "a inline virtual function!"<< endl;
}
virtual inline int func(int x,int y){
return x + y;
}
int a;
};
inline int func1(int x, int y){
return x + y;
}
int main(){
base bb;
cout << bb.func(2, 3) << endl;
cout <<func1(2, 3) << endl;
return 0;
}
再来看看汇编码:
cout << bb.func(2, 3) << endl;
009B649F mov esi,esp
009B64A1 push 9B13E3h
009B64A6 push 3
009B64A8 push 2
009B64AA lea ecx,[bb]
009B64AD call base::func (09B14E7h)
cout <<func1(2, 3) << endl;
009B64D7 mov esi,esp
009B64D9 push 9B13E3h
009B64DE push 3
009B64E0 push 2
009B64E2 call func1 (09B14ECh)
可以看出两个函数都没有被处理成内联函数!!!!!