1.下面程序段的输出结果是
1
2
3
|
char
*p1 = ”
123
”, *p2 = ”ABC”, str[
50
] = “xyz”;
strcpy(str +
2
, strcat(p1, p2));
printr(“%s\n”, str)
xyz123ABC z123ABC xy123ABC 出错 |
2、有以下程序
1
2
3
4
5
6
|
#include <stdio.h>
main(){
int
i=
0
;
i=~i;
printf(
"%d\n"
,i);
}
|
程序运行后的输出结果是?
8
0
1
-1
p++ ->n
(++p) ->n
(a+1) ->n
(p+1) ->n
语句int a[8] = {0}; 是合法的
语句 int a[] = {0};是不合法的,遗漏了数组的大小
语句 char a[2] = {"A", "B"}; 是合法的,定义了一个包含两个字符的数组
语句 char a[3]; a = "AB"; 是合法的,因为数组有三个字符空间的容量,可以保存两个字符
内联函数的主要解决程序的运行效率问题。
内联函数的定义或声明必须出现在内联函数第一次补调用之前。
内联函数中可以包括各种语句
对内联不可以进行异常接口声明
'\0'表示字符0
"a"表示一个字符常量
表达式:'a' > 'b'的结果是"假"
'\"'是非法的
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承
如果一个方法被声明为final,可以被覆盖
finally在异常处理时提供 finally 块来执行任何清除操作。
Java使用 finalize() 方法在垃圾收集器象从内存中清除出去之前做必要的清理工作
1
11
-1
30
vector
list
deque
stack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include<iostream>
using
namespace
std;
class
Base
{
int
x;
public
:
Base(
int
b): x(b) {}
virtual
void
display()
{
cout << x;
};
};
class
Derived:
public
Base
{
int
y;
public
:
Derived(
int
d): Base(d), y(d) {}
void
display()
{
cout << y;
}
};
int
main()
{
Base b(1);
Derived d(2);
Base *p = & d;
b.display();
d.display();
p->display();
return
0;
}
121 222 122 运行出错 |
12、“引用”与多态的关系?
|
两者没有关系
引用可以作为产生多态效果的手段
一个基类的引用不可以指向它的派生类实例
以上都不正确
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class
CTest
{
public
:
CTest():m_chData(‘\0’),m_nData(0)
{
}
virtual
void
mem_fun(){}
private
:
char
m_chData;
int
m_nData;
static
char
s_chData;
};
char
CTest::s_chData=’\0’;
|
16 4
16 10
12 9
10 10
char a=12
int a=12.0
int a=12.0f
int a=(int)12.0
构造函数声明为虚函数
派生关系中的基类析构函数声明为虚函数
构造函数中调用虚函数
析构函数中调用虚函数
通过运算符重载,可以定义新的运算符
有的运算符只能作为成员函数重载
若重载运算符+,则相应的运算符函数名是+
重载二元运算符时,必须声明两个形参
1
2
3
4
5
6
7
8
9
10
|
public
int
bsearch
(
int
[] data,
int
x,
int
y,
int
v) {
int
m;
while
(x<y){
//1
m = x + (y-x)/2;
//2
if
(data[m] == v)
return
m;
//3
else
if
(data[m] > v) y = m;
//4
else
x = m;
//5
}
return
-1;
//6
}
|
是
否
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
using namespace std;
class A{
public:
virtual void f() { cout <<
"A::f() "
; }
void f() const { cout <<
"A::f() const "
; }
};
class B : public A {
public:
void f() { cout <<
"B::f() "
; }
void f() const { cout <<
"B::f() const "
; }
};
void g(const A* a) {
a->f();
}
int main(int argc, char *argv[]) {
A* p =
new
B();
p->f();
g(p);
delete
(p);
return
0;
}
|
B::f() B::f() const
B::f() A::f() const
A::f() B::f() const
A::f() A::f() const
dynamic_cast
reinterpret_cast
static_cast
const_cast
10000000000000000000000000000001 求反 11111111111111111111111111111110
加1 就是 11111111111111111111111111111111
在内联函数中不允许使用循环语句(for,while)和switch结果,带有异常接口声明的函数也不能声明为内联函数。另外,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。
6、
A 选项中, '\0' 表示结束; B 选项中,字符常量是用单引号括起来的一个字符; D 选项中, '\"' 是双引号符。因此 C 选项正确。
7、
final
修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
finally
异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。一般异常处理块需要。
方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
Java中所有类都从Object类中继承finalize()方法。
当垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法。
8、
9、该函数的作用是将两个数相加num1^num2为两个数相加不带进位的结果(num1&num2)<<1为两个数相加的进位值递归调用将进位值加到相加结果上,不断递归知道进位为0为止,结果为num1与num2相加的值
C++ STL 的实现:
1.vector 底层数据结构为数组 ,支持快速随机访问
2.list 底层数据结构为双向链表,支持快速增删
3.deque 底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问
4.stack 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
5.queue 底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
6.45是适配器,而不叫容器,因为是对容器的再封装
7.priority_queue 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现
8.set 底层数据结构为红黑树,有序,不重复
9.multiset 底层数据结构为红黑树,有序,可重复
10.map 底层数据结构为红黑树,有序,不重复
11.multimap 底层数据结构为红黑树,有序,可重复
12.hash_set 底层数据结构为hash表,无序,不重复
13.hash_multiset 底层数据结构为hash表,无序,可重复
14.hash_map 底层数据结构为hash表,无序,不重复
15.hash_multimap 底层数据结构为hash表,无序,可重复
vector表示一段连续的内存区域,随机访问效率很高,因为每次访问离起始处的位移都是固定的,但是在随意位置插入删除元素效率很低,因为它需要将后面的元素复制一遍。 list表示非连续的内存区域,并通过一对指向首尾元素的指针双向链接起来,从而允许向前和向后两个方向进行遍历。在list的任意位置插入和删除元素的效率都很高:指针必须被重新赋值,但不需要用拷贝元素来实现移动。他对随机访问支持不好,需要遍历中间的元素。每个元素有两个指针的额外空间开销。 deque(双端队列,发音为'deck')也表示一段连续的内存区域,但是他支持高效的在其首部插入和删除元素。 选择顺序容器类型的一些准则: 如果我们需要随机访问一个容器,则vector要比List好得多。 如果我们一直要存储元素的个数,则vector又是一个比list好的选择。 如果我们需要的不只是在容器两端插入和删除元素,则list显然比vector好。 除非我们需要在容其首部插入和删除元素,否则vector要比deque好。
12、引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。
【例】:
class A;
class B:public A{……};
B b;
A &Ref = b; // 用派生类对象初始化基类对象的引用
在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个int则占用4字节而不是5字节。
如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间
虚函数因为存在一个虚函数表,需要4个字节,数据成员对象如果为指针则为4字节,注意有字节对齐,如果为13字节,则进位到16字节空间。
sizeof的本质是得到某个类型的大小,确切的来说就是当创建这个类型的一个对象(或变量)的时候,需要为它分配的空间的大小。而类也可以理解为类似于int、float这样的一种类型,当类中出现static成员变量的时候,static成员变量是存储在静态区当中的,它是一个共享的量,因此,在为这个类创建一个实例对象的时候,是无需再为static成员变量分配空间的,所以,这个类的实例对象所需要分配的空间是要排除static成员变量的,于是,当sizeof计算类的大小的时候会忽略static成员变量的大小A:构造函数不能声明为虚函数的原因是: 1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。
- 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
- 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
- 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。 C++提供4个类型转换函数:reinterpret_cast(在编译期间实现转换)、const_cast(在编译期间实现转换)、stactic_cast(在编译期间实现转换)、dynamic_cast(在运行期间实现转换,并可以返回转换成功与否的标志)。
- 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
- 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
- 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
- 当需要重载运算符具有可交换性时,选择重载为友元函数。
17、
-
上下标没有写清楚,题目所指的应该是[x,y),这样5应该是m-1而在下标为[x,y]的情况下,1,4,5都是有问题的。。。。正确版本应该是这样吧while(x<=y) {m = x + (y-x)/2; //2if(data[m] == v) return m; //3else if(data[m] > v) y = m-1; //4else x = m+1; //5}补充:这里下标是个坑,记住上限有没有包含就可以对付1,4,5处的问题(熟记理解两个版本的代码区别),然后是2,写成x+(y-x)/2是防止xy都很大的情况下x+y越界。这样的话应对二分查找应该够了
18、在实际中,使用对象引用作函数参数要比使用对象指针函数更加普遍,这是因为使用对象引用作函数参数具有用对象指针函数参数的优点,而用对象引用作函数参数更加简单,更直接。
19、由于f()在基类中声明为虚的,则p->f()根据对象类型(B)调用B::f(),此时编译器对虚方法使用动态联编,输出B::f()。
dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理, 即会作一定的判断。 对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针; 对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。 reinterpret_cast这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现。 static_cast静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。 const_cast这个转换好理解,可以将常量转成非常量。