c++备忘录2

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)  
可以看出两个函数都没有被处理成内联函数!!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值