1. 用代码说明在标准C++中如何进行输入输出,并解释各语句的含义是什么?
#include <iostream>
using namespace std;
int a,b;
int main()
{
cin >> a >> b;
cout << "hello world" << endl;
return 0;
}
在输入时,从键盘输入的数据先放在键盘缓冲区中,当按回车键时,键盘缓冲区中的数据输入到程序中的输入缓冲区,形成$cin$流,然后用流提取运算符
>>从输入缓冲区中提取数据送给程序中的有关变量。当用$cout$和流插入运算符
<<向显示器输出数据时,先将这些数据送到程序中的输出缓冲区保存,直到缓冲区满了或遇到$endl$,就将缓冲区中的全部数据送到显示器显示出来。
2. 阐述C++中函数三种调用方式的实现机制、特点及其实参、形参格式,最好用代码说明。试比较三种方式的执行效率。(提示:传址、传值、引用传递)
- 传值: 实参用变量名(或常数),形参用变量名
传值调用: 是单向的,实参把值拷贝一份给形参,形参值的改变不会影响实参
代码
#include <iostream>
using namespace std;
void swap(int a,int b)
{
int temp;
temp=a,a=b,b=temp;
cout << "a=" << a << " b=" << b << endl;
}
int main()
{
int i,j;
cin >> i >> j;
swap(i,j);
cout << "i=" << i << " j=" << j << endl;
return 0;
}
运行结果
运行时输入2 5
a=5 b=2
i=2 j=5
- 传指针: 实参用地址,形参用指针
传址调用:是双向的,把实参的地址传给形参,形参就指向实参变量,因此形参的改变会影响实参
代码
#include <iostream>
using namespace std;
void swap(int *a,int *b)
{
int temp;
temp=*a,*a=*b,*b=temp;
cout << "a=" << *a << " b=" << *b << endl;
}
int main()
{
int i,j;
cin >> i >> j;
swap(&i,&j);
cout << "i=" << i << " j=" << j << endl;
return 0;
}
运行结果
运行时输入2 5
a=5 b=2
i=5 j=2
- 传引用: 实参用变量名,形参用引用
引用调用:形参是实参的别名,形参的改变也会影响实参,注意,实参只能用变量名,不能用常量
代码
#include <iostream>
using namespace std;
void swap(int &a,int &b)
{
int temp;
temp=a,a=b,b=temp;
cout << "a=" << a << " b=" << b << endl;
}
int main()
{
int i,j;
cin >> i >> j;
swap(i,j);
cout << "i=" << i << " j=" << j << endl;
return 0;
}
运行结果
运行时输入2 5
a=5 b=2
i=5 j=2
- 效率问题:在内置类型当中三种传递方式的效率上都差不多;在自定义类型当中,传引用的更高效一些,因为它没有对形参进行一次拷贝
3. 什么是内联函数?为什么要使用内联函数?
- 定义: 当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置。
- 原因: 省去了调用的过程,加快程序运行速度(实现代码的重用,提高开发效率),但是可能使得程序的体积变大。
4. 什么是类的前向声明?使用类的前向声明时,要注意什么?
类的前向声明: 是在引用未定义的类之前,声明该类,使编译器知道是一个类名。当程序中使用这个类名时,编译器就不会认为是错误,而类的完整定义可以在程序的其他地方。
注意事项:
- 前向声明的类不能定义对象。
- 可以用于定义指向这个类型的指针和引用。
- 用于申明使用该类型作为形参或返回类型的函数。
类相互引用的循环依赖情况
class B;//类的前向声明
class A{//A类定义
public:
void f(B b);//以B类对象b为形参的成员函数
};
class B{//B类定义
public:
void f(A a);
};
5. 什么是先验条件(Precondition),什么是后置条件(Postcondition)?
- 先验条件($Precondition$): 针对方法($method$),它规定了在调用该方法之前必须为真的条件
- 后置条件($Postcondition$): 针对方法($method$),它规定了方法顺利执行完毕之后必须为真的条件
6. 什么是名称空间(namespace)?它的主要作用是什么?要使用一个名称空间中声明的标识符,方式有哪些?
- 定义: 名称空间通过定义一种新的声明区域来创建命名的名称空间,一个名称空间中的实体不会和另外一个名称空间中的同名实体冲突.
- 作用: 处理程序中常见的同名冲突
例子
#include <iostream>
using namespace std;
namespace mfc{
int a;
//...
}
namespace owl{
int a;
//...
}
int main()
{
mfc::a=5;
cout << "mfc::a= " << mfc::a << endl;
owl::a=3;
cout << "owl::a= " << owl::a << endl;
return 0;
}
运行结果
mfc::a= 5
owl::a= 3
- 方法
- 直接使用域解析符
::.mfc::a=5; owl::a=3; - 使用$using$ $declaration$(声明),一般用于单个元素类型.
using mfc::a;
a=5;
cout << "mfc::a= " << a << endl;
owl::a=3;
cout << "owl::a= " << owl::a << endl;
- 使用$using$ $directive$(指令),一般用于整体名字空间.
using namespace mfc;
a=5;
//...直接使用mfc中的成员(可不用域解析符)
owl::a=3;
7. 什么是重载(Overloading),解释并举例说明?能否根据返回值不同,对函数进行重载,为什么?
重载: 一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载($Overloading$)
void print(int i);
void print(string st);
void print(int i, int j);
原因: 不能根据返回值不同,对函数进行重载,容易产生歧义,当$main$函数调用Fun(1,2),编译器不知道选择哪个函数进行调用
int Fun(int a, int b);
long Fun(int a, int b);
Fun(1,2);
8. 如何防止一个头文件被多重包含?举例说明
使用条件编译
假设包含的文件名为x.h,写成如下:
#ifndef _x_h
#define _x_h
//...其他内容
#endif
9. dynamic-cast的作用是什么?试举例说明

作用: 将基类的地址转换为派生类的地址,如果类型匹配则转换成功,否则转换失败,返回空地址。
转换原则:
- 如果$p$是一个指向$B$类型的对象的指针,则转换成功;
- 如果$p$不是一个指向$B$类型的对象的指针,则转换失败,返回一个空地址.
dynamic_cast<B *>(p);
例子
#include <iostream>
using namespace std;
class A {
public :
virtual void say() {
cout << "Class A" << endl;
}
};
class B : public A {
public :
virtual void say() {
cout << "Class B" << endl;
}
};
class C : public A {
public :
virtual void say() {
cout << "Class C" << endl;
}
};
int main() {
int op;
cin >> op;
A *p;
switch (op % 2) {
case 0: p = new B(); break;
case 1: p = new C(); break;
}
//判断p到底是什么对象
//将p转换为目标地址B *
cout << dynamic_cast<B *>(p) << endl;
//将p转换为目标地址C *
cout << dynamic_cast<C *>(p) << endl;
return 0;
}