1,函数模板缺省情况下都是内联的 需要进一步的学习
- 父类析构函数为非虚函数,子类为虚函数_zhl11a的专栏-CSDN博客_父类的析构函数是非虚的
- 父类析构函数为非虚函数,子类为虚函数 delete子类指针(指向这个子类对象)会调用父类的析构函数
#include <iostream>
using namespace std;class Base
{
public:~Base(){cout<<"~Base()"<<endl;}};class ABase : public Base
{
public:virtual ~ABase(){cout<<"~ABase()"<<endl;}};int main(){Base *pBase = new ABase;delete pBase;//此处出错getchar();return 0;}
assert断言
- assert断言是用来检查非法情况而不是错误情况的,用来帮开发者快速定位问题的位置。如果表达式为假(0),那么首先向错误流strerr打印一条错误信息,然后通过abort函数终止程序的运行。NDEBUG宏打开状态时assert宏是可用的。默认情况下,assert宏只有在Debug版本才起作用,而在Release版本中将被忽略。但在许多操作系统的C程序中,Release版本中也将NDEBUG宏依然为打开状态。 断言不是用于处理错误情况的
- 断言assert函数,C语言assert函数完全攻略
- C/C++ 学习笔记八(断言与异常处理) - 云+社区 - 腾讯云
类的析构函数可以是虚函数 但是构造函数不可以
- 调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数
- 纯虚拟函数是用来提供函数接口的,虚拟函数是用来提供函数接口和默认的函数操作,非虚拟函数是用来提供函数操作的。
- 构造函数,析构函数可不可以是虚函数?_学海无涯-CSDN博客
类中有指向其他资源的指针,且这个资源由类本身进行释放,那么可以使用编译系统生成的默认构造函数进行对象的复制
- C++有关拷贝构造函数(默认/浅/深拷贝构造函数) - Hk_Mayfly - 博客园
子类可以访问父类的保护成员,子类友元类可以通过子类对象去访问父类的保护成员
#include <iostream>class father{
protected:int father_protected = 123;
public:int father_public = 456;
};class son : public father{
public:void print_protected(){std::cout << father_protected << std::endl;}void print_public(){std::cout << father_public << std::endl;}int wed = 123;friend class son_friend;
};class son_friend{
public:void friend_print(son son1){
// std::cout << son1.wed << std::endl;
// son1.print_public();son1.print_protected();}
};
int main(){son son1;son1.wed = 456789;son_friend ofo;ofo.friend_print(son1);
}
两个指针p和q,指向同一个数组,则他们可以进行关系运算,例如p<q,p!=q,指针可以做减法操作,指针可以同整数相加减 正确
int a[10]={0,1,2,3,4,5,6,7,8,9};int *p = a;int *q = &a[9];std::cout << "p和q之间的距离是:" << q-p << std::endl;std::cout << "在p的基础上移动 8个距离后的数值为:" << *(p+8) << std::endl;
判断以下定义是否正确 错误
- 使用const进行修饰 因此在函数的内部 不可以对元素进行修改,去掉const 编译通过
class Date{
private:int d,m,y;
public:int year() const {return y++;};
};
const 成员函数
- 如果不使用const修饰符 就会造成对于函数的返回数组进行修改
class A{
private:int data;
public:A(int num):data(num){};~A(){};int& get_data(){return data;}
};int main(){A a(1);a.get_data() = 4;std::cout << a.get_data() << std::endl;
}
- 使用const进行限定 阻止对于参数的修改
class A{
private:int data;
public:A(int num):data(num){};~A(){};const int& get_data(){return data;}
};int main(){A a(1);
// a.get_data() = 4;// 不允许std::cout << a.get_data() << std::endl;
}
class A{
private:int data;
public:A(int num):data(num){};~A(){};int& get_data(){return data;}
};int main(){const A a(1);
// a.get_data() = 4;// 不允许get_data(a);//错误std::cout << a.get_data() << std::endl;
}
- a 是一个const 对象, 它调用了 get_data 方法,所以函数签名应该是: get_data(a){} 而 a是一个 const 对象, 我们默认的 this 指针并不是 const 类型,所以参数类型不匹配, 编译无法通过! 这下我们终于清楚了, const 修饰成员函数, 根本上是修饰了 this 指针。
-
补充一点,如果成员函数同时具有 const 和 non-const 两个版本的话, const 对象只能调用const成员函数, non-const 对象只能调用 non-const 成员函数。
- 梳理c++ const 修饰函数 - 知乎
子类没有定义构造函数,则调用父类的无参数的构造方法,否则不调用父类无参构造函数
- 在C++中子类继承和调用父类的构造函数方法_菜头-CSDN博客_c++子类构造函数调用父类构造函数
- 子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法,因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法
- 如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建
- 如果子类没有定义构造方法,则调用父类的无参数的构造方法
- 如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法,然后执行自己的构造方法
- 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数
- 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数
- 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)
- 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式
// 子类无构造方法 则调用父类的无参数的构造方法
class father_1{
public:father_1(){std::cout << "father 1 create!\n";}
};class children_1 : public father_1{};
int main(){children_1 children1;
}
//子类定义了构造函数 则先调用父类的构造函数 再次调用子类的构造函数
class father_1{
public:father_1(){std::cout << "father 1 create!\n";}
};class children_1 : public father_1{
public:children_1(){std::cout << "children_1 create!\n";}
};
int main(){children_1 *child = new children_1();}
虚函数是可以内联的吗?可以减少函数调用的开销,提高效率
- C++面试题:虚函数(virtual)可以是内联函数(inline)吗?_changyi9995的博客-CSDN博客
- 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。
- 内联是在发生在编译期间,编译器会自主选择内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。
inline virtual
唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如Base::who()
),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。
class Base{
public:inline virtual void who(){std::cout << "I am Base\n";}virtual ~Base();
};class Derived : public Base{
public:inline void who(){std::cout << "I am Derived\n";}
};
int main(){// 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,// 编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。Base b;b.who();// 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,// 所以不能为内联。Base *ptr = new Derived();ptr->who();// 因为Base有虚析构函数(virtual ~Base() {}),//所以 delete 时,会先调用派生类(Derived)析构函数,//再调用基类(Base)析构函数,防止内存泄漏。delete ptr;ptr = nullptr;}
- 链接给的例子 将析构函数定义为虚函数,但是会出错,除了删除的方式以外,还可以将其定义为default的方式
- virtual ~Base() = default;
class Base{
public:inline virtual void who(){std::cout << "I am Base\n";}virtual ~Base() = default;
};class Derived : public Base{
public:inline void who(){std::cout << "I am Derived\n";}
};
int main(){// 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,// 编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。Base b;b.who();// 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,// 所以不能为内联。Base *ptr = new Derived();ptr->who();// 因为Base有虚析构函数(virtual ~Base() {}),//所以 delete 时,会先调用派生类(Derived)析构函数,//再调用基类(Base)析构函数,防止内存泄漏。delete ptr;ptr = nullptr;}
C++命名空间必须要指定名字 错误 可以
- C++/C++11中命名空间(namespace)的使用_网络资源是无限的-CSDN博客_c++ namespace
- 未命名的命名空间(unnamed namespace):是指关键字namespace后紧跟花括号括起来的一系列声明语句。未命名的命名空间中定义的变量拥有静态生命周期:它们在第一次使用前创建,并且直到程序结束才销毁。
- 一个未命名的命名空间可以在某个给定的文件内不连续,但是不能跨越多个文件。每个文件定义自己的未命名的命名空间,如果两个文件都含有未命名的命名空间,则这两个空间互相无关。如果一个头文件定义了未命名的命名空间,则该命名空间中定义的名字将在每个包含了该头文件的文件中对应不同实体。和其它命名空间不同,未命名的命名空间仅在特定的文件内有效,其作用范围不会横跨多个不同的文件。
一个类可以有多个构造函数 但是只能有一个析构函数
- 理一理C++的构造函数 - 知乎
二叉树的前序、中序后续遍历 常常使用递归的方式来实现
- 二叉树遍历的递归实现详解(先序、中序、后序和层次遍历) - violet-evergarden - 博客园
友元函数破坏了类的封装性
#include机制用于将源程序片段收集在一起,形成一个完整的编译单元作为编译器的输入。
- C++笔记(随时更新)_小明喜欢写bug的博客-CSDN博客 163条
关于纯虚函数 说法正确的是
- 具有纯虚函数的类称为虚基类 错误 虚基类是指虚继承的基类,主要解决的是从不同路径多次继承同一个基类的问题,与纯虚函数无关
- 具有纯虚函数的类不能创建类对象 正确
- 一个基类说明有纯虚函数,其派生类一定要实现该纯虚函数 错误 可以不实现纯虚函数,那么子类也将作为 纯虚类
- 纯虚函数是一种特殊的虚函数 他是个空函数 错误 ,空函数是指不执行任何语句直接返回的函数,显然纯虚函数不满足
- 纯虚函数是一种特殊的虚函数,它是个空函数_百度知道
选择正确的语句是:
int main(){char* pBuf = new char(20);sprintf(pBuf,"%s","This is a test.\n");printf("%s",pBuf);delete pBuf;
};
编译过程中处理#include的语句的阶段是
- 预编译 感觉是预编译阶段,但是没有找到明确的答案
- 语法分析
- 词法分析
- 二进制代码
错误的赋值表达式
int mian(){int a[10];int*p = nullptr;//赋值表达式的位置p = &a;//错误,因为a就代表了地址 即 a的含义等效于a[0]p = &a[0];*p = 1;p = a;}
设置虚基类的目的是为了
- 消除二义性
- 设置虚基类的目的是(__牛客网
多重继承定义:
- 一个派生类(D)有2个或2个以上的基类(B和C);
- 多重继承引起的二义性:
- 假如上述这些基类(B和C)具有相同的基类A,A中的成员数据和成员函数,最终都会以双份的形式拷贝到类D中,
- 那么调用的时候就会出现二义性问题。
虚基类:
- 专门用来解决多重继承引起的二义性问题;(可以理解为D直接从A继承)
- 虚基类的具体实现的注意细节有很多,这里不再列举了,我认为只需要了解原理即可。
下列常量定义正确的是
const int VERSION = 200;const int g_xx[4] = {1,2,4,8};const char* const hh = "Hello world";
不确定enum Color{BLUE,RED};const enum Color gg =BLUE;
const enum Color gg =BLUE;
// gg = RED; //错误 被const修饰,不可以更改const char* const hh = "Hello world";
关于命名空间的理解正确的是 搜查
- 通过使用声明引入的元素名字会遮蔽名字相同的非局部声明
- 表达式::a 一般表示引用全局作用域中声明的元素a
- 使用关键字namespace定义的命名空间必须要有显示的名字必须是独一无二的 错误,可以不需要显示的名字
- 名字空间是可以嵌套的 ✅
继承 和访问之间的关系
- C++继承:公有,私有,保护 - csqlwy - 博客园
程序执行后会有错误或者什么效果?
- 数组访问越界会出现什么情况?栈溢出
- 堆栈溢出就是不顾堆栈中数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据。
- c/c++ 栈溢出、越界、泄漏_kevin的博客-CSDN博客_c++栈溢出
- 【堆栈和栈溢出】MSP430 数组填充越界引起的栈溢出 导致程序跑飞 - bandaoyu - 博客园
- Address Sanitizer 用法 - 简书 重点
#include <iostream>
#include <vector>#define MAX 255
int main(){
// unsigned char A[MAX];
// for (int i = 0; i <= MAX+8; ++i) {
// A[i] = 'c';
// }unsigned char j = 'a';std::vector<char>temp(MAX,'\0');for (int i = 0; i <= MAX; ++i) {temp.at(i) = j;}for (int j = 0; j <= MAX; ++j) {std::cout << temp[j] << " ";}
}
关于动态库和静态库的说法 正确的是
- 程序运行的时候不需要静态库 正确
- 静态库在程序编译的时候会被连接到目标代码中 错误,静态库编译的时候会被直接拷贝,动态库是被链接
- 动态库在程序运行时才被载入 正确
- 动态库 在程序编译的时候不会被连接到目标代码 错误
补充
- 库是一段编译好的二进制的代码,加上头文件供别人进行调用
- 使用库 的场景:1,不希望别人看到源码,以库的方式进行封装,只需要暴露头文件;减少编译的时间,因为库是已经编译好的二进制的代码,编译的时候只需要简单的的link,不需要浪费编译的时间
静态库
- windows下是lib,linux下是.a,静态库在编译的时候会被直接拷贝一份,复制到目标代码里面,这段代码在目标程序里面就不会被改变了;静态库的好处是 编译完成之后库文件就不会有作用了,目标程序没有外部依赖,直接就可以运行,缺点就是使得目标体积变大
动态库
- 动态链接库,win下是dll,linux下是so,mac下是dylib。动态库在编译的时候不会被拷贝到目标程序中,目标程序只会存储动态库的引用。只有程序运行的时候才会被加载;动态库不需要拷贝到目标程序中,不会影响目标程序的体积,同一份库文件可以被多个程序共用。编译才会被载入的特性,因此随时可以对其进行替换。但是 动态加载会带来性能的损耗,使用动态库很依赖外部的环境,缺库会导致程序无法运行。
参考链接
- 静态库与动态库的区别_sheng_bin的博客-CSDN博客_动态库和静态库的区别
const 和 宏 的区别
- 宏缺少类型检查,const具备严格的类型审查 正确
- 宏在编译链接和运行的时候没有符号,const常量在编译和调试的时候(打开编译器调试开关)可见
- 宏定义在函数的内部,函数作用域结束后仍然可用,const常量只在作用域内可见
- 宏在编译阶段展开 const常量在编译阶段处理 错误;宏在预处理阶段,const变量在编译阶段进行处理
C++类不占据内存 只有实例化对象之后才会占据内存
- c++关于类到底占不占内存的问题,书上说类是不占内存的,对象时占内存的。_百度知道
C++语言中提供了哪些代码重用的方式()
- 继承
- 多态
- 模板
关于运算符重载,下列说法不正确的是
- 重载时, 运算符的操作个数可以改变 错误
- 重载时,操作符的优先级可以改变 错误
- 重载时,运算符号的功能可以改变 正确
- 重载时,运算符号的结合性可以改变 错误
注意事项
- 不是所有的运算符号都可以被重载
- 重载运算符号 不可以改变其优先级和结合性
- 重载不会改变运算符的用法,原有的操作数、操作数在左边还是在右边都不会被改变
- 运算符重载不能有默认的参数
- 运算符重载既可以作为类的成员函数,也可以作为全局函数
- 箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载
- 有关运算符重载正确的描述是()。 __牛客网
虚函数说法正确的是
- 成员函数被声明为虚函数之后,其派生类的同名函数都自动转换成 虚函数 正确
- 虚函数不可以有函数体 错误 纯虚函数在函数可以拥有函数体,但是类中只可以写纯虚函数的声明,纯虚函数的定义必须写在类外
- 通常,如果一个类可以被继承,构造函数和析构函数都有必要被定义为虚函数。错误,析构函数一般可以被定义成虚函数,但是构造函数是绝对不可以被定义为虚函数
- 虚函数在基类中可不实现,但是派生类中必须实现 错误 派生类也可以不实现
- 我难道不配拥有函数体吗?---【纯虚函数函数体】_Alice_lihao的博客-CSDN博客