有待补充和纠正。。。。。
1、重写overrid和重载overload的区别,c语言不能重载
overrid是指基类有虚函数,子类重写了这个虚函数
overload是每个类内部的函数之间的重载
redefining 基类的函数不是虚函数,子类重新定义了这个同类型的函数,而覆盖父类的
2、类的关系is-a和has-a的区别, is-a是继承,has-a是组合,组合的耦合性小,推荐使用。
3、可变参数列表用省略号(...)。
4、强制类型转换:
static_cast 用于普通类型转换
const_cast 用于const或volatile转换
reinterpret_cast 转换成完全不同的意思,如将一个类对象转换成一个整形对象
dynamic_cast 用于动态类型转换,父类指针转换成子类指针,需要有虚函数
5、const和define的区别
define创建常量时,不进行类型检查,也不能获得地址,从定义的地方到文件结束可以持续
使用,没有作用域限制。
const修饰的常量和变量一样,只是值不能改变。有类型检查,可以获得地址,有作用域限
制。
6、typedefine和define的区别
define重命名的类型只能用于当前变量,如 define P int * P a, b只有a是指针
typedefine是对类型起了个别名,可作用于所有的变量,如typedefine int* P; P a,b;
a,b
都
是指针类型。
7、void*说明:
在C语言中既可以将void类型的指针赋给任何指针,任何指针也可以赋给void*;
在C++中只能将任何指针赋给void*,而不能直接将void*赋给其他指针,要强制类型转
换。
8、对于一个空类,它的大小为1而不是0。因为如果是0,则紧跟他创建的对象有相同的地址,导
致错误,为了每个对象必须有唯一的地址,大小应该为非0,一般为1。
9、不要在头文件中放置使用命令,如using namespace std; 容易导致命名冲突。
10、友元必须先声明再使用
11、class A{}; A a();是错误的,这里是个函数,不是定义一个对象
12、占位符的作用:目的在于以后可以修改函数定义而不需要修改所有的函数调用。如果加上名
字而不使用,编译器会产生警告
13、const的定义的变量编译器并不为它创建空间,而是保存在符号表里。但是如过取地址或有
extern修饰,则会分配空间。
为了使别的文件也可以使用const修饰的数据,要定义为:extern const int mun = 12;
C语言的const是外连接的,因此可以只声明不初始化: const int bufsize;
在C++中必须是初始化的或者extern声明。
14、函数的常量引用形参可以接受临时变量,非常量引用则不可以
15、const修饰的对象必须调用const修饰的成员函数,否则会出现错误。
16、被关键字mutable修饰的成员变量可以在const修饰的成员函数里改变而不引发任何错误
17、volatile关键字修饰的数据 告诉编译器不要擅自作出有关该数据的任何假设,优化期间尤
其
如
此,每次取数据都要到内存中取,不要使用寄存器的数据。
18、只有static const一起修饰的成员变量才能有初始值 。
19、内联函数和宏的区别
宏存在的问题是:易产生展开错误; 宏不能访问类的私有成员
内联函数类似不同函数,唯一区别就是内联函数会在适当的地方展开,不需要函数调用的
开
销。
任何在类中定义的函数自动地成为内联函数。 对于非类的函数,必须使函数体和声明结合
在
一起才有效,如inline int plusOne(int x) { return ++x; }
20、引用和指针的区别
引用其实就是常量型指针。T &p 等价于 T * const p;
引用被创建时必须被初始化,非常量指针则可以在任何时候被初始化;
一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用,非常量指针
可
以在任何时候指向另一个对象;
不能有NULL引用,必须确保引用是和一块合法的存储单元关联。
21、关于函数存数是引用的说明
当实参类型是常量时,函数的形参类型必须是常量引用,否则编译器会报错,这是为了不
修
改实参。当传递的是临时变量时,也必须是常量形参。 const int a = 12; 如果没有
const
是非法的。
22、不存在用户定义的运算符,即不能编写目前运算符集合中没有的运算符。
23、重载函数应该是成员函数还是非成员函数
运算符
|
建议使用
|
所有的一元运算符
|
成员
|
= () [] -> ->* |
必须是成员
|
+= -= /= *= ^= &= |= %= >>= <<=
|
成员
|
所有其他二元运算符
|
非成员
|
24、explicit关键字用于构造函数:必须显式调用构造函数,避免自动类型转换。
25、对象分配的内存可以存在的地方:
静态存储区:存储空间在程序开始之前就分配好了,在整个程序的运行期间都有效;
栈:在某个作用域范围内有效,出了作用域就会被销毁;
堆:动态分配内存,可以在任何时候决定分配内存及分配多少内存,也要程序自己负责释
放
内存。成存期由程序员选择决定,不受范围影响。
26、malloc 和new的区别
malloc是库函数,不在编译器的控制范围之内;按字节分配内存的;返回的是void*的指
针,
需要强制类型转换;不会调用构造函数
进行初始化,必须自己进行初始化;
new是C++的关键字,运算符;按类型分配内存;返回该类型的指针;调用构造函数进行初
始
化;即有内置的长度计算、类型转换、安全检查。
malloc分配失败会返回NULL,new分配失败会抛出bad_alloc异常,当然也可以没控制new不
抛
出异常 new(nothrow) int[100]; 这样分配失败也会返回NULL
27、delete可以用于删除对象的指针是0,它不做任何事情。建议在删除指针后立即把指针赋值
为
0以避免对它删除两次。
delete void类型的指针可能会出错,因为它不能调用析构函数
28、构造函数、析构函数、operator=不能被继承,每个类有自己的这些函数。
29、静态成员函数不能是虚函数,可以被子类继承。
30、对于成员函数的重写和重定义
如果成员函数是虚函数,则是重写,但是函数的返回值不能改变,而不是虚函数的成员函
数
则可以在子类中改变返回值。
31、构造函数不能是虚函数,析构函数在多态中要为虚函数。
在构造函数和析构函数中使用虚函数不能产生多态特性,只会调用本地版本的函数
32、对于异常处理try---catch
在匹配的catch程序块执行完后程序会恢复到正常的控制流。
33、一般不允许析构函数抛出异常
abort函数被调用时,全局对象和静态对象的析构函数不会被执行。
构造函数也不要抛出异常,否则对于没有创建成功的对象不会代用析构函数。对于构造函
数
没有执行完毕的程序不会创建对象,因此也不会调用析构函数,容易产生内存泄漏。
在构造函数中非要产生异常时,要提前释放相关的资源。
34、异常
exception类主要派生出两个类:logic_error和runtime_error,这两个类的头文件
<stdexcept>, 还有另外的两个派生类bad_alloc和bad_cast
从logic_error派生的异常类
|
domain_error 报告违反了前置条件
|
invalid_argument 抛出这个异常的函数接收到了一个无效的参数
|
length_error 程序试图产生一个长度大于等于环境尺寸大小的最大可能值
|
out_of_range 报告一个参数越界错误
|
从runtime_error派生的异常类 |
overlow_error 算术溢出错误
|
underflow_error 下溢出
|
range_error 违反了后置条件
|
bad_alloc 是内存分配失败抛出的异常,在头文件<new>中定义
bad_cast 在运行时类型识别中发现程序执行了一个无效的动态类型转换(dynamic_cast)
表
达式
35、为了节省空间,C++采用了写时复制的策略,当一个对象拷贝给另一个对象时,他们是公用
一
个对象的内存,只有当有写操作时,才会创建各自的拷贝。
36、关于多继承
工程中一般不使用多继承,多继承容易产生二义性,代码维护较为复杂。
虚继承:共享它们相同的基类,被共享的基类称为虚基类。在这种机制下,不论虚基类在
继
承体系中出现了多少次,在派生类中都只包含唯一一个共享的虚基类对象。
在虚派生中,虚基类是由最底层的派生类初始化的。