本文重点在理清简答题的概念。根据老师发的课件整理了一下,因为我们学校简答题占60%,所以这里全部整理了出来,其他学校的同学可以根据需要看一看。实际上这门语言还是很重实战的,有时候看很久课本或网课不如上手打一个类效果来的好。
cout<<"hello!"<<"world";
cin>>a>>b;
cin
流,然后用流提取运算符“>>
”从输入缓冲区中提取数据送给程序中的有关变量。cout
和流插入运算符“<<
”向显示器输出数据时,先将这些数据送到程序中的输出缓冲区保存,直到缓冲区满了或遇到endl
,就将缓冲区中的全部数据送到显示器显示出来。**C++
中函数三种调用方式的实现机制、特点及其实参、形参格式,最好用代码说明。试比较三种方式的执行效率。(提示:传址、传值、引用传递)Precondition
),什么是后置条件(Postcondition
)?namespace
)?它的主要作用是什么?要使用一个名称空间中声明的标识符,方式有哪些?名字空间实质上是一种作用域。名字空间是一种描述逻辑分组的机制,是为了解决C++
中的变量、函数命名冲突而服务的。
直接指定标识符
#include <iostream>
std::cout << "hello!!"<< std::endl;
使用using关键字进行声明
#include <iostream>
using std::cout;
using std::endl;
最方便的就是使用指令using namespace std;
#include <iostream>
using namespace std;
Overloading
),解释并举例说明?能否根据返回值不同,对函数进行重载,为什么?C++
允许用同一函数名定义多个函数,这些函数的参数个数和参数类型不同。
int max(int a,int b, int c);
double max(double a,double b,double c);
long max(long a,long b,long c);
不能根据返回值不同进行重载。
因为调用时不能指定类型信息,编译器不知道你要调用哪个函数。
如果a.h
和b.h
都包含了一个头文件x.h
。那么x.h
在此也同样被包含了两次,只不过它的形式不是那么明显而已。
#include "a.h"
#include "b.h"
可以使用条件编译。
#ifndef _X_H
#define _X_H
..//(头文件内容)
#endif
当头文件第一次被包含时,它被正常处理,符号_X_H
被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略。
dynamic-cast
的作用是什么?试举例说明。dynamic_cast < Type-id > ( expression )
该运算符把expression转换为type-id类型,并且可以在运行期间检测类型转换是否安全。dynamic_cast
要求转型的目的类型必须是指针或者引用。将基类指针转换为派生类指针,将基类引用转换为派生类引用;
转换是有条件的
如果指针(或引用)所指对象的实际类型与转换的目的类型兼容,则转换成功进行;
否则如执行的是指针类型的转换,则得到空指针;如执行的是引用类型的转换,则抛出异常。
对比面向过程具有抽象、封装、继承和多态的特点。
封装是将抽象得到的数据和行为相结合,形成了一个有机整体,使得一部分成员充当类与外部的接口,而将其他成员隐藏了起来达到了对成员访问权限的合理控制,使得不同类之间的影响最小,加强数据安全,简化编程。
继承允许在保持原有类特性的基础上,进行更具体、更详细的说明,能够很好反映出特殊概念和一般概念之间的关系,是代码复用的基础机制。
多态使得一段程序能够具有处理多种类型对象的能力,相同的消息在不同的对象下会有不同的动作,增强了编程的灵活性。
封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的函数代码进行有机结合,形成类。
作用:使一部分成员充当类与外部的接口,而将其他成员隐藏起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而保护数据增强数据的安全性和简化程序编写工作。
public
/ protected
/ private
分别进行修饰,这三种成员在什么情况下是可以被访问的?类中没有用public
/ protected
/ private
修饰的成员,其可访问性是什么,结构体中没有用public
/ protected
/ private
修饰的成员,其可访问性是什么?public
修饰的成员可以在任何地方被访问private
修饰的成员只能由该类中的函数、其友元函数访问;不能被任何其他访问,该类对象也不能访问。protected
修饰的成员可以被该类中函数、子类函数、友元函数访问;但不能被该类对象访问。private
,struct
默认为public
。Class scope
)、文件作用域(file scope
)、函数作用域(function scope
)?x.m
或X::m
(访问静态成员)ptr->m
,其中ptr
为指向X类的一个对象的指针static
关键字。static
可以避免一个文件中的全局变量与其它文件中的变量同名而发生冲突。this
指针,其作用是什么?this
指针是一个隐含于每一个成员函数中的特殊指针。它是一个指向正在被该成员函数操作的对象,也就是要操作该成员函数的对象。通过this指针可以访问当前对象的所有成员。static member function
)中不能使用 this
指针?this
指针是相当于一个类的实例的指针,this
是用来操作对象实例的内容的,既然静态成员函数和变量都是独立于类的实例对象之外的,他就不能用this
指针。也不能操作非静态成员。default constructor
)?什么情况下,类中会有缺省构造函数?copy constructor
)的参数必须是按引用传递(by reference
)而不能是按值传递(by value
)?A
的拷贝构造函数是以值方式传递一个类 A
对象作为参数的话,当需要调用类 A
的拷贝构造函数时,需要以值方式传进一个 A
的对象作为实参;而以值方式传递需要调用类 A
的拷贝构造函数;结果就是调用类 A
的拷贝构造函数导致又一次调用类A的拷贝构造函数,这就是一个无限递归。A=B
。这时,如果B中有一个成员变量指针已经申请了内存,那 A
中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时 A
内的指针就是野指针了,出现运行错误。Global scope objects
)的构造函数、析构函数分别是什么时候被调用的?自动局部对象(Automatic local objects
)的构造函数、析构函数分别是什么时候被调用的?静态局部对象(static local objects
)的构造函数、析构函数分别是什么时候被调用的?main()
函数返回后全局对象才被销毁,析构函数在程序结束前最后被调用。main
终止或调用exit
函数时调用。Initialization Sections
)?它的作用是什么?(提示:一般数据成员的初始化、常量成员的初始化,对象成员构造函数的选择、父类构造函数的选择等)。构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
class A
{
public:
int a;
float b;
A(): a(0),b(9.9) {} //构造函数初始化列表
};
初始化列表作用:一般数据成员的初始化、常量成员的初始化,对象成员构造函数的选择、父类构造函数的选择。
~
’。作用:清空并释放对象先前创建或者占用的内存资源。
析构函数对象消亡时即自动被调用。
如果析构函数不被声明成虚函数,则编译器采用的绑定方式是静态绑定,在删除基类指针时,只会调用基类析构函数,而不调用派生类析构函数,这样就会导致基类指针指向的派生类对象析构不完全。
若是将析构函数声明为虚函数,不管派生类的析构函数前是否加virtual
(可以理解为编译器优化),都构成重写。基类的指针指向派生类的对象,然后调用重写虚函数——析构函数,构成了多态,而多态与类型无关,只与对象有关,所以就能够调用的就是派生类的析构函数了。
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
class A
{
public:
A(){ i++; }
~A(){ i--; }
int get(){ return i; }
private:
static int i;
};
int A::i(0);
int main()
{
A c;
A b;
A e;
cout<<c.get()<<endl;
A *p=new A;
cout<<c.get()<<endl;
delete p;
cout<<c.get()<<endl;
return 0;
}
C++
中的三大函数(The Big Three
)?Big Three
: 是指 如果一个类要实现下面某一个成员函数,一般都要一起实现另外两个:
Desconstructor
析构函数copy constructor
拷贝构造函数operator =
赋值函数const
定义常量与用使用define
定义常量相比,有什么优点?const
常量有数据类型,而宏常量没有数据类型。编译器可以对const
常量进行类型安全检查,而对宏常量只能字符替换const
常量进行调试,对宏常量不能调试const
定义的常量在程序运行的过程中只有一份拷贝,而define
定义的常量在内存中有若干拷贝。C++
中如何进行静态类型转换,解释并举例说明。用于类层次结构中基类和派生类之间指针或引用的转换。进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
class Base { };
class Derived:public Base {};
int main()
{
Derived D;
Base* B = static_cast<Base*> (&D);
return 0;
}
将派生类型的指针转化为基类型的指针。
用于基本数据类型之间的转换,如把int
转换成char
,把int
转换成enum
。这种转换的安全性也要开发人员来保证。
double a;
int b=100;
a = static_cast<double> (b);
定义常量
const int val = 5;
int const val = 5;
修饰指针
const int* p; //指针p指向的内容是常量,不可改变。
int* const p; //指针本身是一个常量,不可改变。
const int* const p; //指针本身和指向的内容都是常量,都不可以改变。
修饰函数参数 void function(const int Var);
表明参数在函数体内不能被修改,但此处没有任何意义,Var
本身就是形参,在函数内不会改变。
const
关键字。修饰函数返回值:与修饰普通变量和指针意义差不多,而在传引用时,如果不希望函数返回值被改变,就可以添加关键字 const
。
在类中使用const
修饰类成员变量
class A{
const int nValue;
}
修饰类成员函数
class A{
void function()const;
}
常成员函数, 它不改变对象的成员变量. 代表只读函数,增加程序的可读性。
常成员函数不能调用类中任何非const
成员函数。
C++
中,static
静态变量的初始化和取值问题?main()
函数和类的构造函数中定义,必须在类外定义。new
的作用是什么?如何申请单个空间?如何申请动态数组?用new
创建类的对象时,会发生哪些操作?必要时,请用代码说明。作用:在堆中申请一段空间,动态分配内存。
申请单个空间 int *i = new int;
申请动态数组 int *a = new int[10];
new
创建类对象需要指针接收,一处初始化,多处使用,作用域是全局,且需要手动释放空间,在堆中动态分配内存,调用构造函数。
delete
的作用是什么?如何删除单个用new
申请的空间?如何删除申请的动态数组?用delete
删除一个类的对象时,会发生哪些操作?必要时,请用代码说明。delete i;
delete []a;
Dangling Pointers
),其危害是什么?Slicing
)?(注意参考讲义)splice
)”关系:当子类对象拷贝到父类对象时,父类对象中只存在父类定义的成员,而不会出现任何子类中的成员。BaseballTeam(const string s[], int si) : Team(si)
public
、protected
、private
成员,哪些在子类中是可以访问的?在公有继承、私有继承、受保护继承三种继承方式下,父类成员中的public
、protected
、private
成员被继承到子类后,其可访问性分别是什么?派生类是否可以继承父类的构造函数和析构函数?public
和protected
是可以访问的,private
不可访问。public
、protected
、private
private
、private
、private
protected
、protected
、private
C++
中是如何解决的?问题1:类DC的对象中存在多个同名成员 x
, 应如何使用?
解决方案:在DC对象调用x时,用作用域标识符说明 x
是属于哪个类的。
class BC0
{
public:
int K;
};
class BC1 : virtual public BC0
{
public:
int x;
};
class BC2 : virtual public BC0
{
public:
int x;
};
class DC : public BC1,public BC2
{
};
void main()
{
DC d; //虚继承使得BC0仅被DC间接继承一份
d.K = 13; // OK
d.BC1::x = 1;
d.BC2::x = 2;
}
问题2:类DC的对象中,存在两份来自类 BC0
的成员 K
,如何区分?
解决方案:在BC1
类和BC2
类继承BC0
时,其前面加上virtual
关键字就可以实现虚拟继承,使用虚拟继承后,当系统碰到多重继承的时候就会先自动加一个BC0
的拷贝,当再次请求一个BC0
的拷贝时就会被忽略,以保证继承类成员函数的唯一性。
class BC0
{
public:
int K;
};
class BC1 : virtual public BC0
{
public:
int x;
};
class BC2 : virtual public BC0
{
public:
int x;
};
class DC : public BC1, public BC2
{
};
void main( )
{
DC d; //虚继承使得BC0仅被DC间接继承一份
d.K = 13; // OK
}
ADT
)?抽象类的作用是什么?抽象类是否可实例化?抽象类的什么样子类可以实例化?Early Binding
,又称为静态联编)?什么是后期绑定(Late Binding
,又称为动态联编)?重载函数是后期绑定吗,如果不是为什么?绑定:程序自身彼此关联的过程,确定程序中的操作调用与执行该操作的代码间的关系。例如把一个标示符名和一个存储地址联系在一起的过程。
用面向对象的术语讲,就是把一条消息和一个对象的方法相结合的过程。
按照绑定进行的阶段的不同,可以分为静态绑定和动态绑定两种。
静态绑定:绑定工作在编译连接阶段完成。
因为绑定过程是在程序开始执行之前进行的,因此也称为早期绑定或前绑定。
在编译、连接过程中,系统就可以根据类型匹配等特征确定程序中操作调用与执行该操作代码的关系,即确定了某一个同名标识到底是要调用哪一段程序代码。
动态绑定:和静态绑定相对应,绑定工作在程序运行阶段完成的。
class A
{
public:
virtual void Get( );
};
class B : public A
{
public:
virtual void Get( );
};
void MyFunction( A * pa )
{
pa->Get( );
}
pa->Get( )
调用的是 A::Get( )
还是B::Get( )
,编译时无法确定,因为不知道MyFunction
被调用时,形参会对应于一个 A
对象还是B
对象。
所以只能等程序运行到 pa->Get( )
了,才能决定到底调用哪个Get()
。
重载函数是静态绑定。
hiding
)、覆盖(overriding
)、重载(overloading)
?对比它们的异同?以C++
代码为例进行说明。若基类 B 定义了非虚方法 m
,同时其派生类 D
也定义了方法m
,此时,我们说派生类方法 D::m
隐藏了继承自基类的同名方法 B::m
。由于函数签名不同,所以二者不构成重置。故D::m
隐藏了B::m
。
class B
{
public:
void m(int x)
{
}
};
class D : public B
{
public:
void m ( )//由于函数签名不同,所以二者不构成重置。
{
}
};
int main( )
{
D d1 ;
d1.m(); // invokes D::m()
//d1.m(10); // ERROR
d1.B::m(10); // OK
return 0;
}
覆盖(override
)是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须同父类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同,当派生类对象调用派生类中该同名函数时会自动调用派生类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。
class B
{
public:
virtual void m()
{
}
};
class D : public B
{
public:
void m ()//重置了基类方法,仍然为虚函数
{
}
};
int main()
{
B*p= new D;
p -> m(); // 动态绑定 D::m()
return 0;
}
重载:如果顶层函数如果同一类中的函数有不同的签名,则函数名可以相同。编译过程中绑定函数调用和对应的函数体。
class C
{
public:
C()
{
} // default constructor
C(int x)
{
} // convert constructor
};
void print( double d );
void print( char * );
int main( )
{
C c1,c2(26);
print(100.123);
print( "100.123" );
}
run-time binding
) ,通过这种机制,实现将函数名绑定到函数具体实现代码的目的。运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
扩展C++
中提供的运算符的适用范围,以用于类所表示的抽象数据类型。同一个运算符,对不同类型的操作数,所发生的行为不同。
运算符重载的函数一般地采用如下两种形式:成员函数形式和友元函数形式。这两种形式都可访问类中的私有成员。
class Complex
{
public:
Complex( )
{
real=0;
imag=0;
}
Complex(double r,double i)
{
real=r;
imag=i;
}
Complex operator+( const Complex & ) const; //重载为成员函数
friend Complex operator+(Complex &c1,Complex &c2); //重载为友员函数
void display( );
private:
double real;
double imag;
};
当重载为成员函数时,会有一个this
指针,指向当前的类,所以只需要一个参数就可以了。
而当重载为全局函数时,将没有隐含的参数this
指针,这样将会多一个参数。
Complex operator +(Complex&);
friend Complex operator+(Complex &c1,Complex &c2);
friend
)函数?为什么要使用友员函数?friend
修饰说明的非成员函数或其它类的成员函数,在它的函数体中能够通过对象名访问 private
和 protected
成员C++
提供的一种对数据封装和数据隐藏的破坏机制。UML
?如何画UML
中的类图?什么是类与类之间依赖关系、关联关系、包含关系?试举例说明这三种类之间的关系。这三种关系如何和UML
图表示?UML
统一建模语言,UML语言是一种可视化的的面向对象建模语言,描述软件模型的静态结构、动态行为及模块组织与管理。UML
图如何画?两个什么样的类可以实现为继承关系?函数模板:
template<class T>
T add( T a, T b )//函数模板
{
return a + b;
}
add<int> ( 10, 17 );//模板实例
complex c1, c2;
add<complex> ( c1, c2 );
函数模板是 对算法相似,但支持的数据类型不同的一组操作的提炼,以提高程序的重用性。
函数模板的实例就是一个用于特定类型的普通函数。
通常,编译器可根据实参类型确定模板参数;
add ( 10, 17 ); // add<int> (10,17);
complex c1, c2;
add ( c1, c2 ); // add<complex>(c1,c2);
类模板:
使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些数据成员函数的参数、返回值和局部变量能够取任意类型(包括系统预定义和用户自定义)
有时候,有两个或多个类,其功能是相同的,仅仅是数据类型不同,可以使用模板类。
template<class T>//声明模板
class Array
{
T* array;
int size;
public:
Array( int );
T& operator[ ]( int );
};
class charArray
{
char *array;
int size;
public:
charArray( int );
char& operator[](int);
};
class intArray
{
int *array;
int size;
public:
intArray( int );
int& operator[](int);
};
C++
中的异常处理机制。要捕获某段代码中的所有异常,应该如何编写代码?C++
用try
和catch
进行异常处理,当try
块出现异常,则catch
中匹配相应的异常处理,若catch
块中没有匹配该异常对象的语句,则转向外一层的try
、catch
语句,若一直退回到主函数都无法处理异常,则由系统调用terminate()
函数终止程序。exception specification
)列出函数可能会抛出所有异常的类型。