当前位置: 首页 > article >正文

Qt 每日面试题 -3

21、static和const的使用

static : 静态变量声明,分为局部静态变量全局静态变量类静态成员变量。也可修饰类成员函数
有以下几类∶

  1. 局部静态变量 : 存储在静态存储区,程序运行期间只被初始化一次,作用域仍然为局部作用域,在变量定义的函数或语句块中有效,程序结束时由操作系统回收资源。

  2. 全局静态变量︰ 存储在静态存储区,静态存储区中的资源在程序运行期间会一直存在,直到程序结束由系统回收。未初始化的变量默认为0,作用域在声明他的文件中有效。

  3. 类静态成员变量 : 被类的所有对象共享,包括子对象。必须在类外初始化,不可以在构造函数内进行初始化。

  4. 类静态成员函数 : 所有对象共享该函数,不含this指针,不可使用类中非静态成员。

const : 常量声明,类常成员函数声明。

  1. const和static不可同时修饰类成员函数

  2. const修饰成员函数表示不能修改对象(变量类型)实例的状态
    (static表示该函数与类(变量类型)的实例没有关系,所以const 与static不能同时使用)

  3. const修饰变量时表示变量不可修改,修饰成员函数表示不可修改任意成员变量

22、指针和引用的异同

指针∶是一个变量,但是这个变量存储的是另一个变量的地址,我们可以通过访问这个地址来修改变量。
引用∶是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行的操作。

  • 相同点∶二者都可以对变量进行修改

  • 不同点∶

    • 1指针可以不必须初始化,引用必须初始化。
    • 2指针可以有多级,但是引用只有一级( int&& a不合法,int** p合法)。
    • 3指针在初始化后可以改变,引用不能进行改变。
    • 4 sizeof指针可以得到指针本身大小,sizeof引用得到的是变量本身大小。
    • 5 指针传参还是值传递,引用传参传的是变量本身。

23、常用数据结构

vector 	:向量,连续存储,可随机访问。
deque 	:双向队列,连续存储,随机访问。
list	:链表,内存不连续,不支持随机访问。
stack	:栈,不可随机访问,只允许再开头增加/删除元素。
queue	:单向队列,尾部增加,开头删除。
set		:集合,采用红黑树实现,可随机访问。查找、插入、删除时间复杂度为O(logn)。
map		:图,采用红黑树实现,可随机访问。查找、插入、删除时间复杂度为O(logn)。
hash_set:哈希表,随机访问。查找、插入、删除时间复杂读为O(1)。

24、谈一谈你对面向对象的理解

C++面向对象编程就是把事物都抽象成一个对象用属性和方法来描述对象的信息。比如定义一个猫对象,猫的眼睛、毛发、嘴巴就可以定义为猫对象的属性,猫的叫声和走路就可以定义为猫对象的方法。

用对象的方式编程,不仅方便了程序员,也使得代码的可复用性、可维护性变好

C++面向对象的三大特性是封装、继承、多态

25、什么场景下使用继承方式,什么场景下使用组合?

  • 继承︰通过扩展已有的类来获得新功能的代码重用方法

  • 组合︰新类由现有类的对象合并成的类的构造方式

使用场景:

  1. 如果二者存在一个"是"的天系,并且一个类要对另外一个类公开所有接口,那么继承是更好的选择
  2. 如果二者间存在一个“有"的关系,那么首选组合
  3. 如果没有找到及其强烈无法辩驳的使用继承的的理由的时候,一律使用组合组合体现为现实层面,继承主要体现在扩展方面。如果并不需要一个类的所有东西,那么就不需要使用继承,使用组合更好。如果使用继承,那么必须所有的都继承,如果有的东西你不需要继承但是你继承了,那么这就是滥用继承。

26、如何理解多态

  • 定义:同一操作作用于不同的对象,产生不同的执行结果。 C++多态意味着当调用虚成员函数时,会根据调用类型对象的实际类型执行不同的操作。

  • 实现:通过虚函数实现,用virtual声明的成员函数就是虚函数,允许子类重写。声明基类的指针或者引用指向不同的子类对象,调用相应的虚函数,可以根据指针或引用指向的子类的不同从而执行不同的操作。

Overload(重载): 函数名相同,参数类型或顺序不同的函数构成重载。

Override (覆盖): 派生类覆盖基类用virtual声明的成员函数。

Overwrite(重写): 派生类的函数重写了与其同名的基类函数。

  • 派生类的函数与基类函数同名,但是参数不同,此时,不论有无 virtual 关键字, 基类的函数将被overwrite(注意别与overload混淆)。
  • 如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类没有virtual关键字,基类函数将被overwrite。(注意别与override混淆)

27、虚函数表

多态是由虚函数实现的,而虚函数主要是通过虚函数表实现的。如果一个类中包含虚函数,那么这个类就会包含一张虚函数表,虚函数表存储的每一项是一个虚函数的地址。该类的每个对象都会包含一个虚指针(虚指针存在于对象实例地址的最前面,保证虚函数表有最高的性能),需指针指向虚函数表。注意:对象不包含虚函数表,只有需指针,类才包含虚函数表,派生类会生成一个兼容基类的虚函数表。

28、分别写出饿汉和懒汉线程安全的单例模式

单例模式∶保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。根据单例对象创建时间,可分为两种模式∶懒汉模式饿汉模式

  • 懒汉模式∶延迟加载,不到万不得已不会去实例化类,也就是说第一次用到类实例的时候才会实例化。
#include<iostream>
#include<mutex>
using namespace::std;
//懒汉模式一:多线程不安全
template<typename T>
class singleton
{
public:
	static T* getInstance()
	{
		if (instance_ == nullptr) {
			instance_ = new T();
		}
		return instance_;
	}
	singleton() = delete;
	singleton(const singleton&) = delete;
	singleton &operator=(const singleton&) = delete;

private:
	static T* instance_;
};

template <typename T>
T* singleton<T>::instance_ = nullptr;

//懒汉模式二:多线程安全
template <typename T>
class singleton2
{
public:
	static T* getInstance()
	{
		if (instance_ == nullptr)
		{
			mutex_.lock();
			if (instance_ == nullptr)
			{
				instance_ = new T();
			}
			mutex_.unlock();
		}
		return instance_;
	}
private:
	singleton2() = delete;
	singleton2(const singleton2&) = delete;
	singleton2& operator=(const singleton2&) = delete;
private:
	static T* instance_;
	static mutex mutex_;
};

template <typename T>
T* singleton2<T>::instance_ = nullptr;

template <typename T>
mutex singleton2<T> ::mutex_;
class Printer
{
	friend class singleton<Printer>;
	friend class singleton2<Printer>;
private:
	Printer() = default;
	Printer(const Printer&) = delete;
	Printer& operator=(const Printer&) = delete;
public:
	void print()
	{
		cout << "Printer" << endl;
	}
};

int main(int argc,char *argv[])
{
	singleton<Printer>::getInstance()->print();
	singleton2<Printer>::getInstance()->print();
}
  • 饿汉模式∶在单例类定义的时候(即在main函数之前)就进行实例化。因为main函数执行之前,全局作用域的类成员变量instance_已经初始化,故没有多线程的问题。
#include <iostream>
#include <mutex>
using namespace::std;
//饿汉模式
template <typename T>
class singleton
{
private:
	singleton() = delete;
	singleton(const singleton&) = delete;
	singleton& operator=(const singleton&) = delete;
public:
	static T* getInstance()
	{
		return instance_;
	}
private:
	static T* instance_;
};

template <typename T>
T* singleton<T>::instance_ = new T();

class Printer
{
	friend class singleton<Printer>;
private:
	Printer() = default;
	Printer(const Printer&) = delete;
	Printer& operator=(const Printer&) = delete;
public:
	void print()
	{
		cout << "Printer" << endl;
	}
};

int main(int argc, char* argv[])
{
	singleton<Printer>::getInstance()->print();
}

29、说出观察者模式类关系和优点

定义了对象之间一对多的依赖,令多个观察者对象同时监听某一个主题对象,当主题对象发生改变时,所有的观察者都会收到通知并更新。

优点︰

  • 抽象耦合:在观察者和被观察者之间,建立了一个抽象的耦合,由于耦合是抽象的,可以很容易扩展观察者和被观察者。
  • 广播通信:观察者模式支持广播通信,类似于消息传播,如果需要接收消息,只需要注册一下即可。

缺点︰

  • 依赖过多:观察者之间细节依赖过多,会增加时间消耗和程序的复杂程度。这里的细节依赖指的是触发机制,触发链条,如果观察者设置过多,每次触发都要花很长时间去处理通知。
  • 循环调用:避免循环调用,观察者和被观察者之间绝对不允许循环依赖,否则会触发二者之间的循环调用,导致系统崩溃。

30、说出代理模式类关系和优点

优点︰

  • 代理模式能将代理对象与真实被调用的自标对象隔离。
  • 一定程度上降低了系统的耦合度,扩展性好。
  • 可以起到保护目标对象的作用。
  • 可以对目标对象的功能增强。

缺点︰

  • 代理模式会造成系统设计中类的数量增加
  • 客户端和目标对象增加一个代理对象,会造成请求处理速度变慢

http://www.kler.cn/a/319826.html

相关文章:

  • catchadmin-webman 宝塔 部署
  • MySQL(5)【数据类型 —— 字符串类型】
  • 多进程/线程并发服务器
  • 鸿蒙HarmonyOS 地图不显示解决方案
  • 阿里云centos7.9服务器磁盘挂载,切换服务路径
  • C++编程技巧与规范-类和对象
  • mysql学习教程,从入门到精通,SQL FULL JOIN 语句(25)
  • mysql离线脚本安装
  • 【C++算法】哈希表
  • vs2022 程序包管理器控制台中文乱码
  • 100个ChatGPT学术指令—助你高效完成文献综述撰写!
  • 深入理解同步和异步与reactor和proactor模式
  • 【递归】5.leetcode 872 叶子相似的树
  • 南开大学联合同济大学发布最新SOTA Occ OPUS:使用稀疏集进行占据预测,最快实现8帧22FPS
  • 什么是服务器日志,日志有什么作用?
  • 2-103 基于matlab的光电信号下血氧饱和度计算
  • Unity3D URP 内置CSM分帧详解
  • 【渗透测试】-灵当CRM系统-sql注入漏洞复现
  • 传输层协议 —— TCP协议(下篇)
  • Spring IoC DI 之 属性注入
  • BottomNavigationView 添加角标
  • c++开发实战之网络编程(一)
  • 三维重建的几何评价指标
  • 面试算法题精讲:求数组两组数差值和的最大值
  • 只出现一次的数字 II
  • Redis:事务