c++ impl 使用接口类

需求 cpp impl ? 解决 impl 使用接口类有两种方式: 接口类只是作为一个壳,需要什么都是直接调用原来的类来实现 接口类是使用虚函数,实现类通过继承来实现 代理类 代理类非常简单,下面这个 WeightProxy 就是壳,具体的实现都在 Weight 里面。 #ifndef WEIGHTPROXY_H #define WEIGHTPROXY_H #include <string> #include <memory> class Weight; class WeightProxy { public: WeightProxy(); ~WeightProxy(); std::string GetInfo(); std::unique_ptr<Weight> m_proxy; }; #endif // WEIGHTPROXY_H #include "Weightproxy.h" #include "Weight.h" WeightProxy::WeightProxy() : m_proxy(new Weight()) { } WeightProxy::~WeightProxy() = default; std::string WeightProxy::GetInfo() { return m_proxy->GetInfo(); } #include <iostream> // std::streambuf, std::cout #include "Weightproxy.h" int main () { WeightProxy w; std::cout << w....

<span title='2023-07-27 18:07:00 +0800 CST'>2023-07-27</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;207 words&nbsp;·&nbsp;RamLife

c++ impl 使用指针实现即 pimpl

需求 cpp impl 是什么? 解决 impl 解决的问题 依赖太多,包含头文件过多,一个头文件修改,一堆源文件都需要重新编译,导致的编译时间过长。 库文件,不喜欢在头文件中暴露太多的内部成员变量等信息给使用着。 简单 pimpl // 使用Pimpl // 在头文件person.hpp中 #include <memory> class Person { public: Person(); private: // Person类的实现细节放置在该前向声明的实现类中。 struct Impl; // 指向实现类Impl的私有指针 std::unique_ptr<Impl> pimpl_; }; // 在源文件person.cpp中 #include "person.hpp" #include "basic_info.hpp" #include <string> #include <memory> struct Person::Impl { std::string name; std::string id; BasicInfo basic_info; }; Person::Person() : pimpl_(std::make_unique<Impl>()) {} 具体的成员变量放到 cpp 文件中,编译为库后,有以下好处: 就算需要修改包含的成员变量,也不需要修改头文件,那么编译的时候,只会编译这个 cpp 文件,其他依赖这个头文件的都不需要重新编译。 使用者并不能从头文件中发现成员变量的细节。 pimpl 更多细节 pimpl 在使用的时候,还会碰到很多需要注意的地方: 析构函数的实现需要完整的类型 移动赋值需要完整类型 移动构造需要完整类型 拷贝构造和拷贝赋值都需要完整类型 所以上面这些都需要放在 cpp 中实现。...

<span title='2023-07-27 17:45:00 +0800 CST'>2023-07-27</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;158 words&nbsp;·&nbsp;RamLife

QT QFutureWatcher 介绍

需求 QFutureWatcher ? 解决 QFutureWatcher 一般是搭配 QFuture, QtConcurrent 来使用,用于检测多线程异步执行计算的进度,方便在主线程上进行展示或者执行其他动作。 配置 watcher watcher_ = new QFutureWatcher<int>; connect(watcher_, &QFutureWatcher<int>::finished, this, &MainWindow::busy_job_finished); 调用子线程来执行 QtConcurrent::run 提供了最简单的子线程执行函数的方法。 auto future = QtConcurrent::run(this, &MainWindow::do_busy_job); watcher_->setFuture(future); int MainWindow::do_busy_job() { return 1; } 执行结果 void MainWindow::busy_job_finished() { // 若有需要, 关闭通知对话框 qDebug() << "busy job finished!"; qDebug() << "the returned value is: " << watcher_->result(); } 参考 在 QT UI 编程中使用 QtConcurrent 和 QFutureWatcher 执行并发任务 使用QFuture类监控异步计算的结果 Qt多线程编程之高级函数 QFutureWatcher:异步运行监视者 Qt多线程:QtConcurrent + QFuture + QFutureWatcher...

<span title='2023-07-23 17:49:00 +0800 CST'>2023-07-23</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;77 words&nbsp;·&nbsp;RamLife

QT QHash 介绍

需求 QHash ? 解决 QHash<Key, T> 是类似于 QMap 的键值对,但是与 QMap 的区别是: QHash 比 QMap 查找更快,但是所需空间更大。 QMap 默认键值升序排序, QHash 任意排序 QMap 键类型必须提供 operator<(), QHash 键类型必须提供 operator==() 和 qHash() 全局哈希函数。 参考 QT之QHash简介 Qt:QHash和QMap区别

<span title='2023-07-23 17:41:00 +0800 CST'>2023-07-23</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;31 words&nbsp;·&nbsp;RamLife

QT 警告 QObject::connect: Cannot queue arguments of type

需求 qt 程序在运行过程中,报了警告 QObject::connect: Cannot queue arguments of type 'qintptr' 解决 跨线程的信号和槽中,如果出现自定义的类型,那么就会报这个问题。解决也很简单。 在使用这个自定义类的信号和槽的类源文件中,增加头文件 #include <QMetaType>. 在这个类的构造函数中添加 qRegisterMetaType #include <QMetaType> TcpSocket::TcpSocket(qintptr socketDescriptor, QObject *parent) : QTcpSocket(parent), socketID(socketDescriptor) { qRegisterMetaType<qintptr>("qintptr"); this->setSocketDescriptor(socketDescriptor); ... } 参考 QObject::connect: Cannot queue arguments of type “xxx"的解决方案 Qt 线程间信号槽传递自定义数据类型(qRegisterMetaType的使用) QObject::connect: Cannot queue arguments of type…【已解决】

<span title='2023-07-23 17:34:00 +0800 CST'>2023-07-23</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;47 words&nbsp;·&nbsp;RamLife

QT QMetaObject 介绍

需求 QMetaObject ? 解决 QMetaObject 是 Qt 的元对象系统,里面保持了类的相关信息,主要的作用是为了在有指针的情况下,获取这个指针具体的类型信息,方便调试;另外也是 Qt 实现信号和槽的基础。毕竟 C++ 只有 dynamic_cast 用来试探子类型, typeid 只能获取类型名称,其他类型相关信息都不能获取。 由于C++是静态类型语言,有关类的信息只在编译期被使用,编译后就不再保留,因此程序运行时无法获取类的信息。这时就需要使用「运行期类型信息」,即 RTTI(Run-Time Type Information)。 参考 Qt中的元对象系统(Meta-Object System) Qt元对象系统:QMetaObject

<span title='2023-07-22 17:57:00 +0800 CST'>2023-07-22</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;24 words&nbsp;·&nbsp;RamLife

c++ warning: hides overloaded virtual function

需求 C++ 中警告: tcp_socket.h:15:10: warning: 'TcpSocket::readData' hides overloaded virtual function qabstractsocket.h:215:12: note: hidden overloaded virtual function 'QAbstractSocket::readData' declared here: different number of parameters (2 vs 0) 解决 这个问题的原因很简单,就是子类里面重载了父类的虚函数,被重载的虚函数在子类中将会被隐藏。 何为隐藏呢,应该是不能使用子类实例直接调用父类被隐藏的函数,调用时必须指定父类命名空间,往深了说也就是编译器如果在子类中发现了要使用的函数的名字,注意,是名字不包含函数签名,只要名字匹配上,就不会再去父类中去寻找这个名字的函数,即便子类中的函数参数不匹配,也不会再去父类中寻找。 原因 注意是防止书写错误,比如下面这个,如果在子类定义的时候,想的是重写 void foo(BookA *), 结果把 A 写成 B 了,那么这个警告就能提醒了。 class BookA; //改动处 class BookB; //改动处 class A { public: virtual void foo(BookA *) { //改动处 cout << "foo of A" << endl; } }; class B : public A{ public: void foo(BookB *) { //改动处 cout << "foo of B" << endl; } }; int main(void) { A *b = new B(); //改动处 b->foo(new BookB()); return 0; } 解决警告 如果确实是需要重载,又不希望有这个警告碍眼,可以使用 private 加上 using 来解决。 private 是为了防止子类的对象来使用父类的这个虚函数。...

<span title='2023-07-22 17:21:00 +0800 CST'>2023-07-22</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;141 words&nbsp;·&nbsp;RamLife

QT qintptr 介绍

需求 qintptr ? 解决 这个是 qt 为了跨平台用的,特别是有些情况,硬件平台可能是 32bit 或者 64bit。 qintptr 表示指针类型,占用空间和 int 一样,依赖于硬件实现, 32bit 平台那就是 32bit, 64bit 平台那就是 64bit。这样在用户代码层面便于统一。 qintptr 和 quintptr 都是指针,只不过一个是 有符号数,一个是无符号数。 qintptr 这个有符号的类型对于 hasing 等情况比较方便。 参考 <Qt help> -> <QtGlobal>::qintptr

<span title='2023-07-22 14:00:00 +0800 CST'>2023-07-22</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;34 words&nbsp;·&nbsp;RamLife

QT 使用基于 libev 的事件调度器 qt_eventdispatcher_libev

需求 qt 使用高性能事件调度器 解决 可以使用基于 libev 的事件调度器 qt_eventdispatcher_libev 安装 qt_eventdispatcher_libev 在源码目录中新建 eventdispatcher_libev 目录,增加 pri 文件。 复制 https://github.com/sjinks/qt_eventdispatcher_libev 的 src 目录中的文件,删除 win32 等无关文件。 在 pro 文件中,添加 pri 文件 编译看是否有错误。 使用 qt_eventdispatcher_libev main.cpp 中添加头文件 #include "eventdispatcher_libev/eventdispatcher_libev.h" 在 main() 最开始的地方添加 QCoreApplication::setEventDispatcher(new EventDispatcherLibEv()); int main(int argc, char *argv[]) { QCoreApplication::setEventDispatcher(new EventDispatcherLibEv()); QCoreApplication a(argc, argv); return a.exec(); } *注: qt help 中说明 QCoreApplication::setEventDispatcher 使用的地方 That is, before QCoreApplication has been instantiated. * 参考 基于 libev 的 Qt 事件调度器:qt_eventdispatcher_libev...

<span title='2023-07-22 10:33:00 +0800 CST'>2023-07-22</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;77 words&nbsp;·&nbsp;RamLife

QT 打开子界面

需求 qt 父界面,如何打开子界面窗口 解决 void MainWindow::on_action_2_triggered() { // 科室 DepartmentManage * department = new DepartmentManage(test_info_, this); department->setAttribute(Qt::WA_DeleteOnClose); department->setWindowTitle("科室管理"); department->exec(); } 参考 QT·页面跳转,怎么切换到另一个界面 QT通过点击按钮弹出新的窗口(新建弹出式窗口) 对话框QDialog

<span title='2023-07-17 11:53:00 +0800 CST'>2023-07-17</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;24 words&nbsp;·&nbsp;RamLife