c++备忘录1

1.reinterpret _cast类型转换

这种转换通常用于两种任何关联的两个对象之间的转换,它通常为操作数的位模式提供比较低层次的重新解释,举个例子:

int main(){
	int a = 1;
	int *p = &a;
	cout << p << endl;
	char ch = 'a';
	int c = reinterpret_cast<short int>(p);
	short int b = static_cast<short int>(ch);
	cout << c << endl;
	cout << b << endl;
	return 0;
}
输出:

0058FE08
-504
97
可以看到FE08的值就是两个低位字节,1111,1110,0000,10000这些二进制位对应的short int值刚好是-504.

2. 不能基于指针本身是否为const来实现函数的重载,例子:

void func(int *p){
	cout << *p << endl;
	cout << "int *p"<< endl;
}

void func( int * const p){
	cout << *p << endl;
	cout << "int const *p" << endl;
}

int main(){
	int a = 1;
	func(&a);
	return 0;
}

报错:

1>  daily_practice.cpp
1>e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(12): error C2084: 函数“void func(int *)”已有主体
1>          e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(7) : 参见“func”的前一个定义
1>e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(19): error C3861: “func”:  找不到标识符
1>
修改:

void func( int * const p) -> void func( const int * p);

3. 关于const和static修饰的变量的存放位置:

int main(){
	//局部const变量
	const int a = 1;
	int *p1 = (int *)&a;
	*p1 = 2;//赋值可以通过
	cout << *p1 << endl;//输出2
	
	//全局const变量
	int *p2 = (int *)&b;
	*p2 = 2;//!出错

	//局部const static变量
	const static int c = 1;
	int *p3 = (int *)&c;
	*p3 = 2;//!!!出错
	cout << *p3 << endl;
	return 0;
}

所以结论是: 局部const变量存放在栈中,全局const变量存放在.rodata只读段,局部const静态变量也存放在.rodata段。

4.插入迭代器

第一种:back_inserter,创建使用push_back实现插入的迭代器.

第二种:inserter,使用insert实现插入操作,除了所关联的容器外,inserter带有第二个实参,指向插入起始位置的迭代器.

第三种:front_inserter,创建使用push_front实现插入的迭代器.

实例:

int main(){
	vector<int> lst = { 1, 0, 3, 0, 5, 6, 0, 8, 9 };
	list<int>lst1 = {1,2,3,4};
	list<int>::iterator iter = find(lst1.begin(),lst1.end(),3);
	replace_copy(lst.begin(),lst.end(),inserter(lst1,iter),0,100);
	return 0;
}
插入之后lst1变成:1 2 1 100 3 100 5 6 100 8 9 3 4


5.面试遇到的一个题:

/*
已知一个长度为n的数组,输入一行下标值,表示数组元素的新下标
例如原来数组元素是:
1 5 3 7 9 2
当输入4 0 5 3 1 2之后,数组变成:9 1 2 7 5 3
就是将原来的4号下标的元素放到现在下标为0的位置,
将原来0号下标的位置放到现在的1号下标的位置

输入:
6
1 5 3 7 9 2
4 0 5 1 3 2
输出:
9 1 2 5 7 3
*/
#include<iostream>  
#include<vector>  
#include<map>  
#include<fstream>
#include<sstream>  
#include<algorithm>
#include<list>
using namespace std;


void exchange(vector<int>&data,map<int,int>&no){
	int size = data.size();
	vector<vector<int>>cir;
	vector<int>tmp;
	int next;
	vector<bool>flag(size,false);
	int now = 0;
	for (int i = 0; i < no.size(); i++){//保存所有的环
		next = no[now];//下一个元素
		if (find(tmp.begin(),tmp.end(),next)==tmp.end()){//如果没有重复的点
			flag[now] = true;
			if (tmp.size() == NULL){
				tmp.push_back(now);
				tmp.push_back(no[now]);
				now = next;
			}
			else {
				tmp.push_back(next);
				now= next;
			}
		}
		else{//若有重复的点
			tmp.push_back(next);
			cir.push_back(tmp);//加入环
			tmp.clear();
			for (int j = 0; j < flag.size();j++){
				if (flag[j]==false){
					now = j;
					break;
				}
			}
		}
	}
	//交换元素
	for (int i = 0; i < cir.size();i++){
		int num = data[cir[i][0]];//第一个要写到其它位置的元素
		for (int j = 0; j < cir[i].size()-1;j++){
			now = cir[i][j];
			next = cir[i][j + 1];
			int temp =data[next];//被覆盖元素
			data[next] =num;
			num = temp;
		}
	}
}

int main(){
	int num,temp,order;
	vector<int>data;
	map<int, int>info;
	ifstream fin("c:\\users\\dell\\desktop\\data.txt");
	while (fin >> num){
		for (int i = 0; i < num;i++){
			fin >> temp;
			data.push_back(temp);
		}
		for (int i = 0; i < num; i++){
			fin >> order;
			info.insert(make_pair(order, i));
		}
		exchange(data,info);
		for (int i = 0; i < data.size(); i++){
			cout << data[i];
		}
		cout << endl;
		data.clear();
		info.clear();
	}
	return 0;
}

6.类类型转换

class one{
public:
	int a;
	one(int x){
		a = x;
		cout << "class ono has excuted constructer!" << endl;
	}
	operator int()const{
		return a + 1;
	}
};


class two{
public:
	int c;
	two(int y){
	c = y;
	cout << "class two has excuted constructer!" << endl;
	}
	operator one()const{
	one obj(3);
	return obj;
	//return c + 2;
	}
};

void func(int x){
	cout << x << endl;
}

int main(){
	two aa(1);
	one cc(aa);
	func(cc);//编译器提示转换不存在,因为从two->int型的转化没有直接定义,如果先转换成one类型,再转换成int型就转换了两次,这是不允许的!!!
	cout << cc.c << endl;
	return 0;
}


所谓的类类型转化,我们可以看到两个类one都用包含int型参数的构造函数,语句two cc(aa)中,先调用operator int()const返回一个整数,然后利用这个整数调用two的构

造函数,生成一个临时的two对象,然后编译器执行位拷贝用aa的值初始化cc. 但语言只允许一次类类型转换!!!此外标准转化可先于类类型转换之前执行!!!

有以下几点需要注意:

(1)如果定义了从two->one类型的转换,那么one类一定要在two前面定义!!!!

(2)如果one类中定义了拷贝够着函数则编译器提示无法共two转化成one &类型。

(3)在c++ primer中提到:虽然转换函数不能指定返回类型,但是每个转换函数必须显式返回一个指定类型的值,例如,operator int返回一个int值,如果定定义operator  

sales_item,它将返回一个sales_item对象,诸如此类;

但是:

	operator one()const{
		return c + 2;
	}
这里返回的是int型的值,个人理解是返回了一个整形的值,但是one类可以利用构造函数产生一个one类的零时对象,下面我们来看看输出:


可以看到

one cc(aa);

这条语句调用了one类的构造函数,这个有点不懂!!!求指点!!!


7.派生类到基类的转换

class base{
public:
	int a;
	base(){
		a = 1;
		cout << "constructer of base class has excuted!"<< endl;
	}
	base(const base &obj){
		a = obj.a;
		cout << "copy constructer of base class has excuted!" << endl;
	}
};

class derived :public base{
public:
	int b;
	derived(int x,int y):b(y){
	
	}
};

void func(base obj){
	cout << obj.a << endl;
}

int main(){
	derived bb(1, 2);
	base cy = bb;
	return 0;
}

输出:


在c++ primer第四版p488中提到:

在用派生类对象调用基类的赋值构造函数或是赋值操作符时,

1.首先将派生类对象转换成基类引用;

2.将该引用作为实参传给赋值构造函数或赋值操作符;

3.相关操作符使用派生类的基类部分分别对调用构造函数或赋值的基类对象的成员进行初始化或赋值;

4一旦操作完成,对象即为基类对象,它包含派生类的基类部分的副本.

但是在这里我们看到,基类对象先是调用派生类的构造函数生成一个临时的基类对象,然后将基类对象转化成基类引用传递给复制构造函数!!!!


8.在构造函数中调用虚函数

class Base
{
public:
	Base(){
		func();
	}
	virtual void func(){
		cout << "base::func" << endl;
	}
};

class derived : public Base{
public:
	derived(){
		func();
	}
	virtual void func(){
		cout << "derived::func" << endl;
		cout << &b<< endl;
	}
	int b;
};

int main(){
	derived a;
	return 0;
}
输出:


可以看到,编译器在构建派生类对象的时候,在执行base的构造函数调用的是基类的虚函数,这样做是为了访问安全。编译器在构建派生类对象的时候首先要构建基类部分,

在基类的构造函数中,将正在构建的派生类对象当做基类对象,调用的是基类的虚函数。如果调用的是派生类的构造函数,那么就会发生错误,由于派生类的部分还没有构建

例如例子中派生类的int  b, b在基类执行构造函数的时候她的位置还没有被确定,那么对一个没有确定位置的变量执行&b会出错!!!!


9.STL算法和函数指针混搭,之后便产生了仿函数:

int nextNum() {
	static int n = 1;
	return n++;
}

int main() {
	// 定义容器和 输出流迭代器  
	vector<int> vecList(8);
	ostream_iterator<int> screen(cout, " ");
	// nextNum 是函数指针,其必须是有返回值无参函数  
	generate(vecList.begin(), vecList.end(), nextNum);
	cout << "vecList :" << endl;
	copy(vecList.begin(), vecList.end(), screen);
	cout << endl;

	generate_n(vecList.begin(), 3, nextNum);
	cout << "vecList :" << endl;
	copy(vecList.begin(), vecList.end(), screen);
	cout << endl;
	return 0;
}
输出:


10.模板类的友元函数重载(例子是借用http://blog.csdn.net/ozwarld/article/details/7770808):

第一种形式:在模板类里面不需要加template<class T1>的声明,只需加<T>或<>,如果尖括号里面有类型,那一定要和template<class T>class Test的T一致

template <class T>
class Test;                        // 模板类前置声明  

template<class T1>
ostream& operator << (ostream& out, const Test<T1>& obj);      // 模板类友元前置声明  

template<class T>
class Test{
public:
	friend ostream& operator << <T> (ostream& out, const Test<T>& obj);       // 模板类友元定义,注意格式"<>" ,告诉编译器这是一个模板类 
	Test(T n = 0) :num(n){}                                                    //只有和Test相同的实例才是类test的友元函数,其中<T>也可以是<>
	Test(const Test<T>& copy){
		num = copy.num;
	}
private:
	T num;
};

template<class T1>
ostream& operator << (ostream& out, const Test<T1>& obj){
	out << obj.num << endl;
	return out;
}

int main(){
	Test<int> t(2);
	cout << t;
	return 0;
}

第二种形式:这种的声明是一般模板友元

template<class T>
class Test{
public:
	template<class S>                    
	friend ostream& operator << (ostream& out, const Test<S>& obj);//在模板类里面声明模板函数,表示函数的任何类型的实例都是Test类的友元函数
	Test(T n = 0) :num(n) {}
	Test(const Test<T>& copy){
		num = copy.num;
	}
private:
	T num;
};
// 注意<class T>和<class S>都行  

template<class Tt>
ostream& operator << (ostream& out, const Test<Tt>& obj){
	out << obj.num << endl;
	return out;
}


int main(){
	Test<int> t(2);
	cout << t;
	return 0;
}

11. 多重继承下基类指针访问方式

class ClassA{
public:
	virtual ~ClassA(){};
	virtual void Function(){
		cout << "ClassA function!" << endl;
	};
};

class ClassB{
public:
	void FunctionB(){
		cout << "ClassB function!" << endl;
	};
	ClassB(){
		b = 1;
	}
	int b;
};

class ClassC : public ClassA, public ClassB{
public:
	virtual void Function(){
		cout << "ClassC function!"<< endl;
	};
	ClassC(){
		c = 1;
	}
	int c;
};

int main(){
	ClassC aObject;
	ClassA* pA = &aObject;
	ClassB* pB = &aObject;
	ClassC* pC = &aObject;
	cout << pA << endl << pB << endl << pC << endl;
	pB->FunctionB();//pB能访问的函数只有FunctionB(),不能访问Function()
	cout << sizeof(ClassC) << endl;
	return 0;
}
输出:


我们可以看到,pB指针只能访问FunctionB(),而不能访问Function(),pA和pC的地址是一样的,但是pB地址不同,这个好理解,在内存布局中,pB所指的那一段没有虚函数指

、针,且虚函数表中的地址也没有被重写,所以pB只能访问自己类中的函数!!!


12.typeid与dynamic_cast

我们知道两者都会进行运行时检测,当我们用基类指针指向派生类对象的时候,可以通过typeid来获取指针指向的实际对象的类型;dynamic_case在进行转换的时候也会检测

被转换指针所指向的实际对象的类型!!

typeid注意情况:

样例1:

class base{
public:
	base(){
		a = 1;
	}
	virtual void Function(){
		cout << "Class base function!" << endl;
	};
	int a;
};

class derived : public base{
public:
	derived(){
		c = 3;
	};
	virtual void Function(){
		cout << "Class derived function!" << endl;
	};
	int c;
};


int main(){
	derived bb;
	base *p = &bb;
	cout << typeid(*p).name() << endl;
	cout << typeid(p).name() << endl;
	return 0;
}
输出:


样例2:

class base{
public:
	base(){
		a = 1;
	}
	void Function(){
		cout << "Class base function!" << endl;
	};
	int a;
};

class derived : public base{
public:
	derived(){
		c = 3;
	};
	void Function(){
		cout << "Class derived function!" << endl;
	};
	int c;
};
输出:


从对比的结果中我们可以看到,在没有虚函数的情况下,即便基类指针指向了派生类对象,它指向对象的类型依然是class base类型,而不是 class derived类

型!!!!说明typeid的运行时检测和虚函数有关!!!

dynamic_cast注意情况:

情形1:

class base{
public:
	base(){
		a = 1;
	}
	virtual void Function(){
		cout << "Class base function!" << endl;
	};
	int a;
};

class derived : public base{
public:
	derived(){
		c = 3;
	};
	void Function(){
		cout << "Class derived function!" << endl;
	};
	int c;
};


int main(){
	base cy; 
	derived bb;
	base *p1 = &bb;
	base *p2 = &cy;
	derived *p3 = dynamic_cast<derived *>(p1);
	derived *p4 = dynamic_cast<derived *>(p2);
	cout << "p3:"<<p3 << endl <<"p4:"<< p4 << endl;
	return 0;
}
输出:



情形2:将基类的虚函数去掉

class base{
public:
	base(){
		a = 1;
	}
	void Function(){
		cout << "Class base function!" << endl;
	};
	int a;
};
错误提示:

1>e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(40): error C2683: “dynamic_cast”:“base”不是多态类型
1>          e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(12) : 参见“base”的声明
1>e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(41): error C2683: “dynamic_cast”:“base”不是多态类型
1>          e:\vs2013 projects\daily_practice.cpp\daily_practice.cpp\daily_practice.cpp(12) : 参见“base”的声明

说明,只有在基类虚函数存在的情况下(多态性存在的情况下),编译器才会在运行时检测基类指针所指的实际对象,否则编译出错!!!!


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值