一套编程题 问答题 1-20

1. 什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的"别名"(alias),对引用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。
引发问题:
1) const 引用和变量是占同一单元吗?
答:不占同一空间。
例:
const int a = 10;
   const int &ref = a;
   cout << &a << endl;      // 0012FF7C
   cout << &ref << endl;        // 0012FF74
 
2) const 引用可以引用什么变量?
答:既可以引用const变量,也可以引用非const变量。
const int a = 10;
const int &ref = a;
int a = 10;
const int &ref = a;
3) 是否可以定义指针的引用和引用的指针?
答:可以定义指针的引用,但不能定义引用的指针。
例:
int  a  =  10;
int  *p  =  &a;
int  * (&q)  =  p; //正确,q为对p的引用,即对指针的引用
int  & (*q)  =  p; //错误,q为指向引用的指针
4) 对数组的引用的写法是什么?
答:
int  a[5]  = {0};
// 注意ref两边括号不可缺少,并且[]中值必须与所引用的数组长度相同,否则出错(见下例)
int (&ref)[5]  = a; 
5) 是否可以定义引用的数组?
答:不可以
int a[5] = {0};
int &ref[5] = a; //错误
 
2. 将“引用”作为函数参数有哪些特点?
答:(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果.但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
补充:拷贝构造函数调用的三种情况:
a)用一个对象初始化另一个对象;
b)函数返回一个对象;
c)函数传递对象作为函数参数。

3. 在什么时候需要使用“常引用”?
答:如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。
常引用声明方式:const  类型标识符  &引用名 = 目标变量名;
Eg:
int a ;
const int &ra = a;
ra = 1; // 错误
a = 1; // 正确
 
string foo( );
void bar( string & s ); 
那么下面的表达式将是非法的:
bar( foo( ) );
bar( "hello world" ); 
原因在于foo( )和 "hello world" 串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型(string& s),这是非法的。
引用型参数应该在能被定义为const的情况下,尽量定义为const 类型。

4. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
答:格式:类型标识符  &函数名(形参列表及类型说明){ // 函数体 }
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生错误!)
规则:
(1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了无所指“的引用,程序会进入未知状态。 当一定要返回时,可以将局部变量声明为static。
(2)可以返回函数内部new分配的内存的引用,但是注意需要手动释放。(见下例)
(3)可以返回类成员的引用,但最好是const。
(4)流操作符重载返回值申明为“引用”的作用:流操作符 << 和 >>,这两个操作符常常希望被连续使用。
(5)在另外的一些操作符中,却千万不能返回引用:+、-、*、/ 四则运算符。它们不能返回引用,主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。
Eg1:
int& fun()
{
    	int * p = new int(4);
    	cout << p << endl;       // 00382C08
    	cout << *p << endl;      // 4
    	return *p;
}
int main()
{
    	int & ref = fun(); // *p的引用
    	cout << &ref << endl;   // 00382C08
    	cout << ref << endl;    // 4
    	//释放
    	int *p = &ref;
   	delete p;       // delete &ref;
   	return 0;
}

5. “引用”与多态的关系?
答:引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。
Eg:
class A;
  class B : class A{...};
  B b; 
A& ref = b;
 
6. “引用”与指针的区别是什么?
答:引用是某个变量的别名。把引用绑定在变量上,引用不是变量,必须给它赋值。不能为空。指针是一种特殊的变量,指针的值是某个变量的地址值,指针可以等于NULL。
一是考虑到存在不指向任何对象的可能,在这种情况下,能够设置指针为空,使用指针;如果不存在指向NULL的可能,使用引用。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高 因为在使用引用之前不需要测试它的合法性。    
二是需要能够在不同的时刻指向不同的对象,在这种情况下,能改变指针的指向,那么应该使用指针;如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么应该使用引用。
A* a = new A;
A* Const pa= &a;  // pa指向a后,其值不能改变
 
7. 什么时候需要“引用”?
答:a)拷贝构造函数的参数:
b)赋值操作符“=”的返回值
c)赋值操作符“=”的参数
d)流操作符“<<”和“>>”

8. 结构与联合有和区别?
答:1) struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员,而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的长度。 
2) 对于union的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于struct的不同成员赋值是互不影响的。
结构体是多个数据的集合,可以保存多个数据;而联合union只保存一个数据,但是可以按照不同类型来读取。 
比如你的联合里面有一个int和一个float,你第一次写进int,然后第二次写进float,那么int就不可用了(或者说读出来已经不是你存的int值了),因为这个union所在的内存区域值已经是第二次写进的float了。
Eg:
#include <iostream>
using namespace std;
 
union A
{
    	int b;
    	float c;
};
 
int main()
{
    	A a;
    	a.b = 1;
    	a.c = 2;       
    	cout << a.b <<endl;     // 1073741824,使用%d的方式查看浮点数2的存储格式
    	cout << a.c <<endl;     // 2    
    	return 0;
}
 
//结构和联合的占用空间计算
#include <iostream>
using namespace std;
union UnionA
{
 	    double i; 
 	    int k[5];
 	    char d;
}; 
struct StructA
{
 		int cat;
 		UnionA cow; 
 		double dog;
} ; 
struct StructB
{
 		int c;
 		char f;
 		double b;
};
 
int main()
{
 		cout << sizeof( UnionA ) << endl;       // 24
 		cout << sizeof( StructA ) << endl; // 40
 		cout << sizeof( StructB ) << endl; // 16   
 		return 0;
}

9. 已知String类定义如下:
class String
{
public:
String(const char *str = NULL); // 通用构造函数
String(const String &another); // 拷贝构造函数
~ String(); // 析构函数
String & operater =(const String &rhs); // 赋值函数
private:
char *m_data; // 用于保存字符串
};

实现如下:
String::String(const char *str)
{
    	if( !str )
    	{
        m_data = NULL;
}
//或者 if( str == NULL )
// {   
//      m_data = new char[1];
//      m_data[0] = ‘\0’;
// }
   	 else
    	{
        m_data = new char[strlen(str)+1];
        strcpy( m_data, str );
  	    }
}
 
String:: String(const String &another)
{
    	m_data = new char[strlen(another.m_data)+1];
    	strcpy(m_data, another.m_data);
}
 
String::~String()
{
    	if( m_data )
    	{
        delete []m_data;
        m_data = NULL;
      }
}

String& String::operator = (const  String  &rhs) 
{ 
//可能会出现String s(“123”); s = s;这种情况,所以需要先判断是否是本身
    	if( rhs == *this )
    	{
        return *this;
    	}
    	if( m_data )
    	{
        delete []m_data;
        m_data = NULL;
    	}
   	 m_data = new char[strlen(rhs.m_data)+1];
    	strcpy(m_data, rhs.m_data);
    	return *this;
} 

10. .h头文件中的ifndef/define/endif 的作用?
答:ifndef/define/endif是预处理命令中的条件编译,作用是防止头文件被重复引用。

11. #include<file.h> 与 #include "file.h"的区别?
答:#include<file.h>调用标准库函数,#include”file.h”先调用用户自定义函数,如果没有找到,会调用标准库函数。

12. 面向对象的三个基本特征,并简单叙述之?
答:1)继承:继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并它允许程序员在保持原有类特性的基础上进行扩展,增加功能,使之更适合特殊的需要。
2)封装:封装(Encapsulation)是面向对象程序设计最基本的特性,把数据(属性)和函数(方法)合成一个整体,对数据的访问只能通过公有的接口访问,封装的对象,这些对象通过一个受保护的接口访问其他对象。
3)多态性:多态性(polymorphism)多态性是指允许不同类的对象对同一消息作出响应。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题,函数的重载,运算符的重载,属于多态性中的编译时的多态性,虚函数属于运行时多态。

13. ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?
应用层 表示层 会话层 传输层 网络层 物理链路层 物理层 
    TCP/UDP属于传输层  
TCP是面向连接的可靠字节流  ;  
UDP是无连接的不可靠报文传递
    TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。 
    与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。
    由于 UDP 比 较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。 
TCP: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好,开销大,实时性较差。         UDP: 包头小,开销小 ,占用资源少,实时性较好,缺点是不可靠。

14. 请简述C、C++、VC、MFC在概念上的区别
C是面向过程编程的语言;
C++是面向对象编程的语言;
VC是微软提供的方便于开发C++程序的一套开发工具。
MFC(Microsoft Function Class),是微软提供的一套函数类库,里面封装了许多Windows API函    数,方便开发者调用。

15. 用什么函数开启新进程、线程。
CreateProccess()创建进程;
   	CreateThread()创建线程
   	MFC中还提供了_beginthread()与_beginthreadex()函数创建线程

16. SendMessage和PostMessage有什么区别
SendMessage:发送消息后,等待消息处理完毕后才继续执行自身的程序。
   	PostMessage:发送消息后不等待消息处理即继续执行自身的程序。

17. WaitForSingleObject 有何作用?
m_pThrd 的类型是CWinThread* 时, WaitForSingleObject(m_pThrd->m_hThread, INFINITE),有何作用?  
WaitForSingleObject是表示等待线程的一个函数。
参数为INFINITE表示一直等待线程CWinThread执行结束后,再继续处理自身程序。

18. __stdcall、__cdecl、__pascal在什么方面有所不同。
这些都是一些函数参数的调用约定,告诉编译器函数参数压栈的顺序,以及压入堆栈的内容由谁来    清除,是调用者还是函数本身清除堆栈的内容。简单列表如下:
Directive  Parameter order  Clean-up Passes parameters  in registers?
    	  pascal      Left-to-right     Routine                     No
       cdecl       Right-to-left     Caller                      No
      stdcall     Right-to-left     Routine                     No

19.请解释“func”为何种类型,这种类型的作用什么,变量ttt 的值是多少?
typedef int (*func)(int, int*);
int xxx(int a, int *p)
{
	return a + *p;
}
int dowork(func aaa, int bbb, int *ccc)
{
	return aaa(bbb, ccc);
}
int sss = 4;
int ttt = dowork(&xxx, 3, &sss);

func表示一个函数指针,它指向参数为int,int*,返回值为int的函数。ttt的值为7

20.请问下述代码中: int operator+(…)起什么作用?this是什么?ccc 的值最终为多少?
class Fruit
{
public:
	Fruit()
	{
		weight = 2;
	}
	Fruit(int w)
	{
		weight = w;
	}
	int operator+(Fruit f)
	{
		return this->weight * f.weight;
	}
private:
	int weight;
};
	Fruit aaa;
	Fruit bbb(4);
	int ccc = aaa + bbb;
int operator+(… )表示重载类的“+”号运算符,this表示对象本身的指针,本例中它指向类的对   象aaa;ccc最终的结果为8(8 = 2 * 4)。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值