C++面试常见问题整理汇总
本文总结讲述了C++面试常见问题。分享给大家供大家参考,具体如下: 1. 继承方式 public 父类的访问级别不变 #include <iostream> using namespace std; class base { public: void printa() { cout <<"base"<< endl; } protected: void printhello() { cout <<"helo"<< endl; } private: void printnohello() { cout <<"no hello"<< endl; } }; class derived : public base { public: void printb() { printhello(); } // void printc() { printnohello(); } //printnohello是父类的私有函数,不可访问 }; int main() { base a; a.printa(); //a.printhello(); //printhello是类derived的protected函数,不可访问。 } 2. sizeof 和 strlen 的区别 ① sizeof 是一个操作符,strlen 是库函数。 #include <iostream> #include <cstdlib> #include <cstring> using namespace std; int main() { int a[] = {1,2,3,4,5}; cout << sizeof(a) << endl; //20 // cout << strlen(a) << endl; char b[] = {'a','b'}; cout << strlen(b) << endl; //6 cout << sizeof(b) << endl; //2 } 3. C中的 malloc 和C++中的 new 有什么区别 new、delete 是操作符,可以重载,只能在 C++中使用。 注意:malloc 申请的内存空间要用 free 释放,而 new 申请的内存空间要用 delete 释放,不要混用。 因为两者实现的机理不同。 4.1. c/c++中static 要理解static,就必须要先理解另一个与之相对的关键字auto,其实我们通常声明的不用static修饰的变量,都是auto的,因为它是默认的。auto的含义是由程序自动控制变量的生存周期,通常指的就是变量在进入其作用域的时候被分配,离开其作用域的时候被释放;而static就是不auto,变量在程序初始化时被分配,直到程序退出前才被释放;也就是static是按照程序的生命周期来分配释放变量的,而不是变量自己的生命周期;所以,像这样的例子: void func() { int a; static int b; } 每一次调用该函数,变量a都是新的,因为它是在进入函数体的时候被分配,退出函数体的时候被释放,所以多个线程调用该函数,都会拥有各自独立的变量a,因为它总是要被重新分配的;而变量b不管你是否使用该函数,在程序初始化时就被分配的了,或者在第一次执行到它的声明的时候分配(不同的编译器可能不同),所以多个线程调用该函数的时候,总是访问同一个变量b,这也是在多线程编程中必须注意的! static的全部用法: 1.类的静态成员: class A { private: static int s_value; }; 在cpp中必须对它进行初始化: int A::s_value = 0; // 注意,这里没有static的修饰! 类的静态成员是该类所有实例的共用成员,也就是在该类的范畴内是个全局变量,也可以理解为是一个名为A::s_value的全局变量,只不过它是带有类安全属性的;道理很简单,因为它是在程序初始化的时候分配的,所以只分配一次,所以就是共用的; 类的静态成员必须初始化,道理也是一样的,因为它是在程序初始化的时候分配的,所以必须有初始化,类中只是声明,在cpp中才是初始化,可以在初始化的代码上放个断点,在程序执行main的第一条语句之前就会先走到那;如果你的静态成员是个类,那么就会调用到它的构造函数; 2.类的静态函数: class A { private: static void func(int value); }; 实现的时候也不需要static的修饰,因为static是声明性关键字;类的静态函数是在该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员,不需要类的实例即可调用;实际上,它就是增加了类的访问权限的全局函数:void A::fun(int); 静态成员函数可以继承和覆盖,但无法是虚函数; 3.只在cpp内有效的全局变量: 在cpp文件的全局范围内声明: static int g_value = 0; 这个变量的含义是在该cpp内有效,但是其他的cpp文件不能访问这个变量;如果有两个cpp文件声明了同名的全局静态变量,那么他们实际上是独立的两个变量; 如果不使用static声明全局变量: int g_value = 0; 那么将无法保证这个变量不被别的cpp共享,也无法保证一定能被别的cpp共享,因为要让多个cpp共享一个全局变量,应将它声明为extern(外部)的;也有可能编译会报告变量被重复定义;总之不建议这样的写法,不明确这个全局变量的用法; 如果在一个头文件中声明: static int g_vaule = 0; 那么会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的;所以也不建议这样的写法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同作用域的变量; 这里顺便说一下如何声明所有cpp可共享的全局变量,在头文件里声明为extern的: extern int g_value; // 注意,不要初始化值! 然后在其中任何一个包含该头文件的cpp中初始化(一次)就好: int g_value = 0; // 初始化一样不要extern修饰,因为extern也是声明性关键字; 然后所有包含该头文件的cpp文件都可以用g_value这个名字访问相同的一个变量; 4.2 C中static有什么作用 ① 隐藏。当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。 5. 简述CC++程序编译的内存情况分配 C、C++中内存分配方式可以分为三种: (1)从静态存储区域分配:内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static变量等。 一个 C、C++程序编译时内存分为 5 大存储区:堆区、栈区、全局区、文字常量区、程序代码区。 6. 面向对象的三大特征 ① 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。 覆盖,是指子类重新定义父类的虚函数的做法。 总结:作用 ① 封装可以隐藏实现细节,使得代码模块化 7. 简述多态的实现原理 编译器发现一个类中有虚函数,便会立即为此类生成虚函数表vtable。虚函数表的各表项为指向对应虚函数的指针。编译器还会在此类中隐含插入一个指针 vptr指向虚函数表。调用此类的构造函数时,在类的构造函数中,编译器会隐含执行 vptr 与 vtable 的关联代码,将 vptr 指向对应的 vtable,将类与此类的 vtable 联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的 this 指针,这样依靠此 this 指针即可得到正确的 vtable。 如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。 注意:一定要区分虚函数,纯虚函数、虚拟继承的关系和区别。牢记虚函数实现原理,因为多态C++面试的重要考点之一,而虚函数是实现多态的基础。 8. c++空类的成员函数 缺省的构造函数 注意:只有当实际使用这些函数的时候,编译器才会去定义它们。 9. 谈谈你对拷贝构造函数和赋值运算符的认识 两个不同之处: ① 拷贝构造函数生成新的类对象,而赋值运算符不能。 注意:当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。 10. 用 C++设计一个不能被继承的类 class Base { private: Base() {} ~Base() {} }; class Derived : public Base { public: Derived() : Base() {} ~Derived() {} }; C++ 中的流对象就是采用这样的原理。防止被赋值、复制。 11. 类成员的重写、重载和隐藏的区别 重写和重载主要有以下几点不同 ① 范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中。 隐藏和重写、重载有以下几点不同 ① 与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中 说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也是完全不同的,覆盖是动态绑定的多态,而重载是静态绑定的多态。 12. extern 有什么作用 extern 标识的变量或者函数声明其定义在别的文件中,提示编译器遇到此变量和函数时在其它模块中寻找其定义。 13. 引用和指针区别 ① 引用必须被初始化,但是不分配存储空间。指针不必在声明时初始化,在初始化的时候需要分配存储空间 14. 数组指针 #include <iostream> using namespace std; int main() { int a[5] = {1,5}; int *ptr = (int*)(&a+1); cout << *(ptr-1) << "t" << *(ptr-2) << endl; // 5 4 cout << "----------------" << endl; int *p = (int *)(a+1); //2 cout << *p << endl; } 15. const int *a 和 int * const a 区别 int main() { int b = 3; int c = 4; const int *p = &b; //等价于 int const *p = &b; p = &c; //修饰值,指针可变 //*p = 5;//error 修饰值,值不可变 cout << *p << endl; int a = 5; int * const q = &a; //修饰指针 //p = &c;//error修饰指针,指针不可变 *p = 5; //修饰指针,值可变 } 希望本文所述对大家C++程序设计有所帮助。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |