QT 信号槽和回调函数的区别

需求 信号槽和回调函数区别 解决 方便 信号和槽相对更加方便。 回调函数和接口在每次使用的时候,都需要额外判断函数指针是否为空。 当需要回调多个函数的时候,还需要管理多个函数指针。 当调用和被调用中间隔了几个类,回调就会很麻烦,需要把指针一路传递过去。 速度 回调函数和接口这样直接使用的明显会更加快速,信号和槽会慢一些。曾经出现一个问题,使用信号和槽在断开连接时只打印一次,使用回调函数会打印两次,经过调试发现,使用信号和槽在调试模式也会打印两次。初步判断是信号虽然触发了两次,但是因为时间过短,所以导致只执行了一次槽函数。 参考

2023-07-28 · 1 min · 11 words · RamLife

c++ 实现类似 java 的 interface

需求 cpp 实现类似 java 的 interface 解决 interface 关键字 因为 interface 所有声明默认都是 public=,所以选择 =struct. #define interface struct; #define implements public 使用 #include "Interface.h" Interface IBar { public: virtual ~IBar(){} virtual int getBarData() const = 0; virtual void setBarData(int nData) = 0; }; class Bar :public BasicBar,implements IBar { public: Bar(int x=0) : BasicBar(x) { } ~Bar(){} virtual int getBarData() const { std::cout <<"Get Bar!"; return 0; } virtual void setBarData(int nData) { } }; class DataAccess { // Construction & Destruction public: DataAccess() { } ~DataAccess() { } static IBar* createBar() { //返回对象给IBar接口 return(new Bar()); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //IBar *bar = new Bar(); IBar *bar = DataAccess::createBar(); bar->getBarData(); delete bar; return a....

2023-07-28 · 1 min · 143 words · RamLife

c++ 工厂设计模式

需求 cpp 工厂模式 解决 https://zhuanlan.zhihu.com/p/83535678 https://zhuanlan.zhihu.com/p/83537599 参考

2023-07-28 · 1 min · 7 words · RamLife

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....

2023-07-27 · 1 min · 207 words · 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 中实现。...

2023-07-27 · 1 min · 158 words · 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...

2023-07-23 · 1 min · 77 words · RamLife

QT QHash 介绍

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

2023-07-23 · 1 min · 31 words · 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…【已解决】

2023-07-23 · 1 min · 47 words · RamLife

QT QMetaObject 介绍

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

2023-07-22 · 1 min · 24 words · 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 是为了防止子类的对象来使用父类的这个虚函数。...

2023-07-22 · 1 min · 141 words · RamLife