C++考研复试题集合

1.名词解释

(1)函数对象
(2)类模板
(3)动态绑定与静态绑定及异同点

先了解什么是多态,多态是指同样的消息被不同类型的对象接受时导致不同的行为,从实现角度来讲分为编译时的多态和运行时的多态,前者是在编译的过程中确定了同名操作的具体操作对象,而后者是在运行过程中才动态确定操作所针对的具体对象,这种确定操作对象的过程就是绑定,就是把一条消息和一个对象的方法相结合的过程,前者是静态绑定,后者是动态绑定,也叫晚期绑定或后绑定。只有虚函数实现的是动态绑定,其它全部是静态绑定。

(4)容器
(5)解释protected的意义和用途

protected关键字声明的成员只能由继承派生类访问,本类外无法访问。

(2)类模板
(2)类模板
(2)类模板

2.简答题

1.复制构造函数是什么?何时调用?系统自动调用默认复制构造函数会出现什么现象?自定义复制构造函数有什么用?

       复制构造函数具有一般构造函数的所有特性,其作用是使用一个已经存在的对象去初始化同类的一个新对象。在三种情况下被调用:一.当用类的一个对象去初始化该类的另一个对象时;二.如果函数的形参是类的对象,调用函数,进行形参和实参结合时;三.如果函数的返回值是类的对象,函数执行完成返回调用者时。默认的复制构造函数实现的是对象间元素的一一对应复制,但是当类的数据成员含有指针时,会将指针也复制过来,这使得两个对象指向同一个内存地址,表面是好像完成了复制,但是实际上待复制对象并没有产生自己真正的副本,这就是所谓的“浅复制”。“浅复制”的危害是,当我们要释放动态申请的内存时,由于两个对象的指针成员均指向同一个地址,会导致同一内存地址被释放两次,造成内存泄漏。因此我们引入“深复制”概念,即我们自己显示定义复制构造函数,确保不会出现不同指针指向同一内存地址的情况。

2.举例说明C++异常处理机制

异常处理的目的是,允许用户排除环境错误,继续运行程序。

#include 
using namespace std;
int divide(int x,int y){

	if(y==0)
		throw x;
	return x/y;
}

int main(){

	try{
	
		cout<<"8/2="<<divide(8,2)<<endl;
		cout<<"8/0="<<divide(8,0)<<endl;
	}
	catch(int e){
	
			cout<<e<<"is divided by zero"<<endl;
	}
	cout<<"That is ok."<<endl;
	return 0;
}

结果:
8/2=4
8is divided by zero
That is ok.
如果始终没有找到与被抛掷异常相匹配的catch子句,最终main函数会结束执行。

3.程序分析

1.全局和主函数局部变量
#include 
using namespace std;
int b=6;
int f1(int &x){

	cout<<b<<endl;//6
	b=b+2;
	x=x+3;
	cout<<x<<endl;//5
	return b;
}
int main(){

	int a=2,b=2;
	b+=f1(a);
	cout<<b<<endl;//10
	cout<<a<<endl;//5
	cout<<::b;//8,::是全局作用域限定符
	return 0;
}
2.文件输出流,复制构造和析构函数
#include 
#include 
using namespace std;
ofstream out("hm.out");
class HM{

	static int oCount;
public:
	HM(){oCount++;}
	static void print(const string& msg=""){
	
		if(msg.size()!=0)
			out<<msg<<":";//out对象是我们自己定义的,不是cout
		out<<"oCount="<<oCount<<endl;
	}
	~HM(){
	
		oCount--;
		print("~HM()");
	}
};

int HM::oCount=0;
HM f(HM x){
	
	x.print("x in f()");
	return x;
}
int main(){

	HM h;
	HM::print("test1");
    HM h2=f(h);//此处是本题最复杂的地方,形参和实参的结合会执行一次复制构造函数,然后f(n)返回时会赋值给h2,此处涉及到第二次复制构造函数的执行。因为本题使用默认的复制构造函数,没有oCount++操作,f(n)执行完毕后,内部的x对象会被析构,
    HM::print("test2");执行析构函数。
	return 0;
}//程序执行完毕,h和h2两个对象会被析构,执行两次析构函数。

运行结果:
test1:oCount=1
x in f():oCount=1
~HM():oCount=0
test2:oCount=0
~HM():oCount=-1
~HM():oCount=-2

3.多态
#include 
using namespace std;
class pet{

	int i;
public:
	virtual void eat()const{
	
		cout<<"pet:eat"<<endl;
	}
	void speak() const{
	
		cout<<"pet:speak"<<endl;
	}
	virtual void sleep(){
	
		cout<<"pet:sleep"<<endl;
	}
};

class goldfish:public pet{

public:
	void eat() const{
	
		cout<<"goldfish:eat"<<endl;
	}
	virtual void speak() const{
	
		cout<<"goldfish:speak"<<endl;
	}
};

int main(int argc,char* argv[]){

	cout<<"sizeof:pet"<<sizeof(pet)<<endl;//8B
	goldfish bob;
	cout<<"sizeof:bob"<<sizeof(bob)<<endl;//8B
	bob.eat();//"goldfish:eat"
	bob.speak();//"goldfish:speak"
	bob.sleep();//"pet:sleep"
	
	pet *p=&bob;
	p->eat();//"goldfish:eat"
	p->speak();//"pet:speak"
	p->sleep();//"pet:sleep"
	return 0;
}

结果:
C++考研复试题集合_第1张图片

4.常类成员

class X{
int a;
public:int func(void){
return a++;
}
};
class Y:public X{
public:void set(int c){
this->a=c;//a是类X的私有数据成员,类Y是无法访问的,所以这里错了
}
int describe() const{//应该去掉const,因为常成员函数不能更新目的对象的数据成员
return func();
}
};

5.运算符重载
#include 
#include 
using namespace std;

template<class T>
class Array{

	enum{size=100};
	T A[size];
	public:
};

void main(){

	Array<string> as;
	as[0]="0";
	for(int i=1;i<as.size();i++){
	
		as[i]+=as[i-1];
	}
}

修改后:

#include 
#include 
#include 
using namespace std;

template<class T>
class Array{
private:
	enum{size=100};
	T A[size];
	public:
		int getsize() const;
		T &operator [](int i);
};
template <class T>
int Array<T>::getsize() const{

	return size;
}

template <class T>
T &Array<T>::operator [](int i){

	assert(i>=0&&i<size);
	return A[i];//返回数组Array[i]的引用
}

void main(){

	Array<string> as;
	as[0]="0";
	int i;
	for(i=1;i<as.getsize();i++){
	
		as[i]+=as[i-1];
	}
	for(i=0;i<as.getsize();i++){
	
		cout<<as[i]<<endl;
	}
}

结果:
C++考研复试题集合_第2张图片

6.定义一个堆栈类模板
#include 
#include 
#include 
using namespace std;
const int MaxStackSize=50;
template<class T>

class Stack{

	private:
		T list[MaxStackSize];
		int top;
    public:
		Stack();
		void Push(const T &item);
		T Pop();
		void Clear();
		const T &Peek() const;
		bool isEmpty() const;
		bool isFull() const;

};
template<class T>
Stack<T>::Stack():top(-1){}

template<class T>
void Stack<T>::Push(const T &item){

	assert(!isFull());
	list[++top]=item;
}

template<class T>
T Stack<T>::Pop(){

    assert(!isEmpty());
	return list[top--];
}

template<class T>
void Stack<T>::Clear(){

	top=-1;
}

template<class T>
const T &Stack<T>::Peek() const{

	assert(!isEmpty());
	return list[top];
}

template<class T>
bool Stack<T>::isEmpty() const{

	return top == -1;
}

template<class T>
bool Stack<T>::isFull() const{

	return top==MaxStackSize - 1;
}

int main(){

	Stack<int> s1;
	int i;
	for (i=0;i<MaxStackSize;i++){
	
		s1.Push(i);
	}
	cout<<"after pushed 50 times the top is:"<<s1.Peek()<<endl;
	for(i=0;i<MaxStackSize-1;i++){
	
		s1.Pop();
	}
	cout<<"after poped 49 times the top is:"<<s1.Peek()<<endl;
	s1.Pop();
	cout<<"isEmptt:"<<s1.isEmpty()<<endl;
	system("pause");
	return 0;

}

结果:
C++考研复试题集合_第3张图片

7.调用形参为引用的函数
#include
void swap(int &a,int &b){

	a=a+b;
	b=a-b;
	a=a-b;
}
void main(){

	int a=19,b=15;
	cout<<"a="<<a<<",b="<<b<<endl;
	swap(&a,&b);//这里错了,应该是swap(a,b)
	cout<<"a="<<a<<",b="<<b<<endl;
}

刚刚看了一遍清华的C++引用课程,有几个点:

(1)引用必须在定义时直接初始化,不能先定义之后再初始化,引用是不可更改的。

(2)函数在调用时候才会给形参分配内存空间,也就是调用之前函数内的局部变量不存在。

综合这两个点知道,在函数调用时才会给形参分配存储空间,那么当函数调用时,这个引用t才被创建,然后立即用实参对其进行初始化,也就是上面写的&t = a;这个操作。也就是在形实结合的时候,这个引用才被定义。

#include
#include 
using namespace std;

template <class T>

void Swap(T &a,T &b){
T temp;
temp=a;
a=b;
b=temp;
}
void main(){

	int a=5,b=9;
	//char s1[]="hello",s2[]="hi";这样调用Swap(s1,s2)交换的是地址,所以错了。
    char *s1="hello",*s2="hi";//这样调用Swap(s1,s2)交换的
	Swap(a,b);
	Swap(s1,s2);
	cout<<"a="<<a<<",b="<<b<<endl;
	cout<<"s1="<<s1<<",s2="<<s2<<endl;
}

你可能感兴趣的:(C++考研复试题集合)