QT之实现简陋聊天

2023-11-12

相关知识:QT,数据库,TCP/IP,Socket;

1.登陆界面
包含登陆和注册两种功能,思路如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200608133411367.png
难点:建立服务器和数据库,数据库保存数据,服务器与数据库产生联系
解决:数据库与服务器放在同一个类中,登陆和注册时,客户端与服务端连接,传输数据给服务端,然后通过数据库来处理数据。

大致步骤:创建ui界面 => {connect(登陆按钮,客户端主动连接服务器),connect(服务器得到新连接,connect(客户端readReady,服务器读取数据))}
=> 客户端写入数据 ->服务器读取数据 => 使用数据库 => 根据数据输出信息/注册账号。

2.实现聊天
如下为基本功能和实现思路:
在这里插入图片描述

参考博文:

  1. https://blog.csdn.net/weixin_40011728/article/details/77924196
  2. https://www.cnblogs.com/yuweifeng/p/9382841.html
  3. https://www.cnblogs.com/lifexy/p/10921958.html

上述博文的内容比我的硬核多了…

新发现一个难点:一个服务器连接多个客户端时,要想清楚怎么去确定不同的客户端,之前的错误代码使得一个客户端登陆,结果包括没连接的客户端都登陆了。

效果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
数据库展示:
在这里插入图片描述

可以说就实现了正常软件基本功能中的一小部分,后续检查发
现注册信息为空没有设置…
如果要优化界面应该不会比做这些功能难,拿QPaint画画,搞些和文件相关的连接应该就可以。
上面两条应该就是体力活了,但是聊天软件本来应该像QQ一样,最起码能加好友,但是我目前没有想好怎么做,这类知识全是第一次接触,可以说大半部分照着参考博文抄来的,查了很多资料去了解各种函数,有时候数据库的操作失败也是莫名其妙的,再继续下去不如系统地学点知识再来做一回。

全部代码如下:
mylogin.h

#ifndef MYLOGIN_H
#define MYLOGIN_H

#include <QWidget>

#include <QTcpServer>
#include <QTcpSocket>

#include <QMessageBox>

#include "myregister.h"
#include "server_sqlite.h"

namespace Ui {
class MyLogin;
}

class MyLogin : public QWidget
{
    Q_OBJECT

public:
    explicit MyLogin(QWidget *parent = nullptr);
    ~MyLogin();
    void clientSend(QString message);

signals:
    void toSignUp();
    void sendContent(QString content);
    void createUi(QString);
    void refreshList(QString);

private slots:
    void signIn();
    void clientRead();
    void updateSign();

private:
    Ui::MyLogin *ui;
    QTcpSocket *clientTcp;
};

#endif // MYLOGIN_H


mylogin.cpp

#include "mylogin.h"
#include "ui_mylogin.h"

MyLogin::MyLogin(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyLogin)
{
    ui->setupUi(this);

    connect(ui->pushButton_Login,&QPushButton::clicked,this,&MyLogin::signIn);
    connect(ui->pushButton_Register,&QPushButton::clicked,this,&MyLogin::toSignUp);

}

MyLogin::~MyLogin()
{
    clientTcp->close();
    delete ui;
}

void MyLogin::signIn(){
    clientTcp = new QTcpSocket(this);

    clientTcp->connectToHost("127.0.0.1",8888);

    if(!clientTcp->waitForConnected(20000)){
        QMessageBox::warning(this,"错误","连接超时");
        return;
    }
   // qDebug()<<"连接服务器成功!";

    QString name = ui->lineEdit_Name->text();
    QString password = ui->lineEdit_Password->text();
    if(""==name||""==password){
        QMessageBox::information(this,"提示","请输入完整登陆信息!");
        return;
    }
    QString tmp = name+";"+password;
  //  qDebug()<<"tmp:"<<tmp;
    clientTcp->write(tmp.toUtf8());//将完整信息写入传递给服务器
    connect(clientTcp,&QTcpSocket::readyRead,this,&MyLogin::updateSign);

//    //登陆成功后连接聊天的信号
//    connect(clientTcp,&QTcpSocket::readyRead,[=](){
//       emit
//    });
//    //connect(clientTcp,&QTcpSocket::readyRead,this,&MyLogin::clientRead);

}

void MyLogin::clientSend(QString message){
    //qDebug()<<"clientSend:"<<message;
    clientTcp->write(message.toUtf8());
}

void MyLogin::clientRead(){
    QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());
    QString content = client->readAll();
    QStringList analysis = content.split("|");
    if("refreshFriendList"==analysis.at(0)){
        emit refreshList(analysis.at(1));
        return;
    }
   //qDebug()<<"emit:"<<content;
    emit sendContent(content);
}

void MyLogin::updateSign(){
    disconnect(clientTcp,&QTcpSocket::readyRead,this,&MyLogin::updateSign);
    connect(clientTcp,&QTcpSocket::readyRead,this,&MyLogin::clientRead);
    QString tmp = clientTcp->readAll();
    QStringList analysis = tmp.split("|");
    emit createUi(analysis.at(1));
}

myregister.h

#ifndef MYREGISTER_H
#define MYREGISTER_H

#include <QWidget>

#include <QTcpSocket>
#include <QTcpServer>

#include <QMessageBox>
#include <QDebug>



namespace Ui {
class MyRegister;
}

class MyRegister : public QWidget
{
    Q_OBJECT

public:
    explicit MyRegister(QWidget *parent = nullptr);
    ~MyRegister();

private slots:
    void signUp();

private:
    Ui::MyRegister *ui;

    QTcpSocket *myReg;
};

#endif // MYREGISTER_H


myregister.cpp

#include "myregister.h"
#include "ui_myregister.h"

MyRegister::MyRegister(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyRegister)
{
    ui->setupUi(this);

    connect(ui->pushButton_Sure,&QPushButton::clicked,this,&MyRegister::signUp);
}

MyRegister::~MyRegister()
{
    myReg->close();
    delete ui;
}

void MyRegister::signUp(){
    myReg = new QTcpSocket;
    myReg->connectToHost("127.0.0.1",8888);
    if(!myReg->waitForConnected(20000)){
        QMessageBox::warning(this,"错误","连接超时");
        return;
    }
    qDebug()<<"连接服务器成功!";

    QString name = ui->lineEdit_Name->text();
    QString pas1 = ui->lineEdit_Password->text();
    QString pas2 = ui->lineEdit_PasswordAgain->text();

    if(pas1 != pas2){
       QMessageBox::warning(this,"警告","两次输入密码不一致!");
       return;
    }

    QString temp = name+";"+pas1+";0";
    myReg->write(temp.toUtf8());
}


server_sqlite.h //服务器&数据库

#ifndef SERVER_SQLITE_H
#define SERVER_SQLITE_H

#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlQuery>
#include <QSqlError>

#include <QTcpServer>
#include <QTcpSocket>

#include <QMessageBox>

#include <QApplication>
#include <QObject>

#include <QDebug>

class Server_Sqlite:public QObject
{
    Q_OBJECT

public:
    Server_Sqlite();
    ~Server_Sqlite();
    void dataInit();
    void getChartRecord();

    QList<QTcpSocket *>onlineClients;//在线用户表
    QList<QString>onlineName;//在线用户昵称

private slots:
    void newClient();
    void serverRead();
    void serverDisconnect();
    void sendMessage();

private:
    QSqlDatabase db;

    QTcpServer *myServer;


};

#endif // SERVER_SQLITE_H


server_sqlite.cpp

#include "server_sqlite.h"

Server_Sqlite::Server_Sqlite()
{
     myServer = new QTcpServer;

     //监听,端口号:8888
     bool isOk = myServer->listen(QHostAddress::Any,8888);

     //监听失败
     if(false == isOk){
         QMessageBox::warning(NULL,"监听","8888监听失败!");
         return;
     }else{
         qDebug()<<"监听成功!";
     }

     //当有客户端连接时候,触发信号:newConnection()
     connect(myServer,&QTcpServer::newConnection,this,&Server_Sqlite::newClient);
}

Server_Sqlite::~Server_Sqlite(){
    db.close();
    myServer->close();
}

void Server_Sqlite::dataInit(){
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(QApplication::applicationDirPath()+"/scooters.dat");     //在本目录下生成
    db.open();

    QSqlQuery query;
//  query.exec("DROP TABLE clients");     //先清空一下表
//  query.exec("DROP TABLE chartRecord");
    if(!query.exec("CREATE TABLE clients ("
                       "name VARCHAR(40) NOT NULL, "
                       "password VARCHAR(40) NOT NULL,"
                       "score INTEGER NOT NULL)")){
        qDebug()<<"clients已被创建或出错!";
    }
                    //创建一个clients表

    query.exec("CREATE TABLE chartRecord ("
               "message VARCHAR(200) NOT NULL)");
}

void Server_Sqlite::newClient(){
    QTcpSocket *clientPort;
    clientPort = myServer->nextPendingConnection();
    //与对应的客户端产生连接
    connect(clientPort,&QTcpSocket::readyRead,this,&Server_Sqlite::serverRead);
    connect(clientPort,&QTcpSocket::disconnected,this,&Server_Sqlite::serverDisconnect);
    onlineClients.push_back(clientPort);
}

void Server_Sqlite::serverRead(){
    QTcpSocket *clientPort =qobject_cast<QTcpSocket *>(sender());

    bool flag = false;
    QList<QTcpSocket *>::iterator it;
    for(it = onlineClients.begin();it != onlineClients.end();it++){
        if((*it) == clientPort){
            flag = true; break;
        }
    }
    if(!flag)return;

    disconnect(clientPort,&QTcpSocket::readyRead,this,&Server_Sqlite::serverRead);
    //获取数据,查询数据库
    QString str = clientPort->readAll();
    qDebug()<<"读入数据"<<str;
    QStringList analysis = str.split(";");//str:name;password
    QString tmp = QString("select * from clients where name = '%1'").arg(analysis.at(0));
    qDebug()<<tmp;
    qDebug()<<"length="<<analysis.length();
    QSqlQuery query;
    query.exec(tmp);
    if(!query.next()){//在数据库中没找到该用户名
        qDebug()<<"没找到!";
        if(analysis.length() == 3){
            query.prepare("INSERT INTO clients (name,password,score) "
                          "VALUES(:name, :password, :score)");
            QString myName = analysis.at(0);
            QString myPassword = analysis.at(1);
            qDebug()<<myName<<myPassword;
            query.prepare("INSERT INTO clients (name, password, score) "
                          "VALUES (:name, :password, :score)");
                            //为每一列标题添加绑定值
                query.bindValue(":name", myName);
                query.bindValue(":password", myPassword);
                query.bindValue(":score", 0 );
                query.exec();               //加入库中
            QMessageBox::information(NULL,"提示","注册成功!");
            return;
        }
        QMessageBox::information(NULL,"提示","该用户尚未注册!");
        return;
    }else{//找到该用户名
        qDebug()<<"找到了!";
        if(analysis.length() == 3){
            QMessageBox::warning(NULL,"警告","该用户名已被注册!");
            return;
        }
        if(analysis.at(1) != query.value(1)){//0:name 1:password 2:score
            qDebug()<<query.value(1).toString();
            QMessageBox::warning(NULL,"提示","密码输入错误!");
            return;
        }else{
              int newScore =query.value(2).toInt()+1;
              tmp = QString("update clients set score = %1 where name = '%2'").arg(newScore).arg(analysis.at(0));
              query.exec(tmp);
        }
    }
   // qDebug()<<"来新客人了";
    onlineName.push_back(analysis.at(0));
    tmp.clear();
    QList<QString>::iterator it2;
    for(it2 = onlineName.begin(); it2 != onlineName.end(); ++it2){
        tmp+=";"+(*it2);
    }
    for(it = onlineClients.begin();it != onlineClients.end();it++){
        (*it)->write("refreshFriendList|"+tmp.toUtf8());
    }
    connect(clientPort,&QTcpSocket::readyRead,this,&Server_Sqlite::sendMessage);
}

void Server_Sqlite::sendMessage(){
        //哪一个QTcpSocketc对象可读就会发出readyRead()信号,通过信号的发出者找到相应的对象
        QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());
        QString str = client->readAll();
        //群发
        QList<QTcpSocket *>::iterator it;
        for(it = onlineClients.begin();it != onlineClients.end();it++){
            qDebug()<<"群发:"<<str;
            (*it)->write(str.toUtf8());
        }
        QSqlQuery query;
        QString tmp = QString("insert into chartRecord (message) values ('%1')").arg(str);
        query.exec(tmp);
}

void Server_Sqlite::serverDisconnect(){//断开连接删去该用户
    QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());
    onlineClients.removeOne(client);
    qDebug()<<"断开连接";
}


widgt.h//聊天窗口

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QObject>

//主窗口用户列表使用
#include <QTextBrowser>
#include <QLabel>

#include "server_sqlite.h"
#include "mylogin.h"
#include "myregister.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void mainCreadUi(QString name);
    void refreshChart(QString content);
    void refreshList(QString names);

private:
    Ui::Widget *ui;
    QTextBrowser *xin;
    QLabel *record;

    Server_Sqlite *serSql;
    MyLogin *log;
    MyRegister *reg;
};
#endif // WIDGET_H


widget.cpp

#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

//    serSql = new Server_Sqlite;
//    serSql->dataInit();

    this->setWindowTitle("群聊窗口");

    log = new MyLogin;

    connect(log,SIGNAL(createUi(QString)),this,SLOT(mainCreadUi(QString)));
    connect(log,&MyLogin::toSignUp,[=](){
        reg = new MyRegister;
        reg->show();
    });

    //发送消息写入聊天框
    connect(ui->pushButton_Send,&QPushButton::clicked,[=](){
       QString fasoner = ui->label_Name->text();
       QString message = ui->textEdit_Send->toPlainText();
       qDebug()<<fasoner<<message;
       log->clientSend(fasoner+":\n"+message);
    });
    connect(log,&MyLogin::sendContent,this,&Widget::refreshChart);
    //查看历史记录
    record = new QLabel(this);
    record->setText("消息记录:");
    record->move(565,40);
    xin = new QTextBrowser(this);
    xin->move(565,60);
    xin->setFixedSize(325,330);

    connect(ui->pushButton_ChartRecord,&QPushButton::clicked,[=](){
        if(ui->pushButton_ChartRecord->text()!="关闭记录"){
        this->setFixedSize(900,405);
        record->show();
        xin->show();
        ui->pushButton_ChartRecord->setText("关闭记录");
        qDebug()<<"数据库数据:";
            QSqlQuery query;
            query.exec("select * from chartRecord");
            while(query.next()){
                QString message = query.value(0).toString();
                xin->append(message);
        }
        }else{
            ui->pushButton_ChartRecord->setText("历史记录");
            record->close();
            xin->close();
            this->setFixedSize(565,405);
        }
    });

    //更新在线列表
    connect(log,SIGNAL(refreshList(QString)),this,SLOT(refreshList(QString)));

    log->show();
}

Widget::~Widget()
{
    qDebug()<<"数据库数据:";
        QSqlQuery query;
        query.exec("select * from chartRecord");
        while(query.next()){
            QString message = query.value(0).toString();
            qDebug()<<message;
    }
    delete ui;
}

void Widget::mainCreadUi(QString names){
    ui->textEdit_Friends->setReadOnly(true);
    QStringList analysis = names.split(";");
    ui->label_Name->setText(analysis.back());
    for(int i=0;i<analysis.length();i++){
        QString tmp = QString("select * from clients where name = '%1'").arg(analysis.at(i));
        int score;
        QSqlQuery query;
        query.exec(tmp);
        while(query.next()){
            score = query.value(2).toInt();//name;passowrd;score
            tmp.sprintf("%-15s%-5d",analysis.at(i).toStdString().data(),score);
            ui->textEdit_Friends->append(QString(tmp));
        }
    }
    QString name = analysis.back();
    this->show();
    log->close();
}

void Widget::refreshChart(QString content){
    ui->textEdit_Send->clear();
    ui->textBrowser_Chart->append(content);
}

void Widget::refreshList(QString names){
    ui->textEdit_Friends->clear();
    QStringList analysis = names.split(";");
    for(int i=0;i<analysis.length();i++){
        QString tmp = QString("select * from clients where name = '%1'").arg(analysis.at(i));
        int score;
        QSqlQuery query;
        query.exec(tmp);
        while(query.next()){
            score = query.value(2).toInt();//name;passowrd;score
            tmp.sprintf("%-15s%-5d",analysis.at(i).toStdString().data(),score);
            ui->textEdit_Friends->append(QString(tmp));
        }
    }
}

最后是main.cpp

#include "widget.h"
#include "server_sqlite.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Server_Sqlite tmp;
    tmp.dataInit();
    Widget w,w2,w3;
  //w.show();
    return a.exec();
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT之实现简陋聊天 的相关文章

  • 数据库报错1264错误

    数据库报错1264 php程序报错1264 这个原因有可能是字段长度不够 改变一下字段长度
  • Install Ubuntu 12.04 on Macbook pro Retina

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 Install rEFIt Download and mount the rEFIt 0 14 dmg disk image Double click on the r
  • log4j 2读取配置文件的三种方法

    log4j 2读取配置文件的三种方法 log4j 2读取的配置文件可以分为三类 src下的配置文件 绝对路径的配置文件 相对路径的配置文件 我们一一给例子 直接看代码 package com herman test import java
  • 【Linux之Shell脚本实战】查询邮政编码与对应地区

    Linux之Shell脚本实战 查询邮政编码与对应地区 一 脚本要求 二 检查本地系统环境 1 检查系统版本 2 检查系统内核版本 三 配置脚本注释模板 1 编辑 vimrc 文件 2 检查模板生效情况 四 编辑shell脚本 1 创建脚本
  • 「数据结构」三步搞定表达式中缀转后缀 手算法 通俗易懂 C语言

    表达式中缀转后缀 举个例子 一个式子 5 20 1 3 14 如何把该式子转换成后缀表达式呢 其实就是分三步 按运算符优先级对所有运算符和它的运算数加括号 原本有括号的不用加 把运算符移到对应的括号后 去掉括号 对应的具体实现为 5 20
  • 音视频开发系列-音视频核心知识精讲

    音视频开发系列 音视频核心知识精讲 1 视频为什么会花屏 2 音频为什么容易有杂音 3 音视频进阶需要掌握什么项目 音视频核心知识 为什么会花屏 容易有杂音 进阶需要掌握什么项目 https www bilibili com video B
  • day09:定时器

    目录 总结 1 三种解绑事件 2 事件冒泡 3 阻止事件冒泡 4 事件委托 事件代理 5 事件的三个阶段 一 最大的匿名函数 二 定时器setInterval 三 一起摇摆案例 四 亮起来案例 五 美女时钟效果 六 进一步优化时钟 七 渐变
  • 我们用4行代码节省了100万 相见恨晚的PCDN

    我们公司主要做视频在线点播 还有少量视频下载 比较关心网络加速 首先就是价格 其次是首播时间 流畅率这几个核心性能指标 目前使用阿里云PCDN也有几个月了 整体结果是超预期 值得安利的 写这篇文章 希望能通过选型对比 接入过程 效果实现几个
  • torchserve使用-注册模型设置参数(二)

    目录 1 自定义处理程序 2 托管多个模型 3 模型接口 3 1 添加注册新模型 3 2 查看是否注册成功 3 3 查看注册模型基本信息 3 4 设置注册模型参数 3 5 使用以下代码注销模型 3 6 模型版本控制 4 记录和指标 1 自定
  • xxl-job-admin多数据库支持

    记录一下改造过程 针对 xxl job 2 3版本 什么是xxl job 你的系统中有很多定时任务 如果你想统一管理 你需要一个调度系统 XXL JOB是一个分布式任务调度平台 其核心设计目标是开发迅速 学习简单 轻量级 易扩展 githu
  • 机器学习初实践——恶意域名检测

    这次恶意域名检测实践是第一次自己做机器学习而非单纯复现 参考了第一次鸢尾花的代码和GitHub的UrlDetect中的特征提取参数的代码 一 数据处理 首先要实现自动化处理数据 在这里我没有使用urlparser而是直接写脚本提取域名 提取
  • 【南邮操作系统实验】页面置换算法 (FIFO、LRU、OPTP)

    写在前面 操作系统内存管理的页面置换算法 因为懒得看老师给的代码 太长了而且据说好像还有错误 就自己写了一个python版本的 因为比较菜 所以写的一般般 仅供大伙参考一下Orz python版本的 代码如下 import random 生
  • mysql视图基本操作

    mysql视图介绍及如何创建视图请看 一个案例理解mysql视图 本章主要记录视图的修改 删除以及展示视图语法 目录 一 创建视图 二 修改视图 三 删除视图 四 更新视图 五 展示视图 一 创建视图 请看 一个案例理解mysql视图 二
  • Docker 使用网络

    文章目录 外部访问容器 端口绑定 映射所有接口地址 映射到指定地址的指定端口 查看当前端口配置 多个端口绑定 容器互联 配置 DNS 外部访问容器 1 使用 P 标记时 Docker 会随机映射一个 490000 49900 的端口到内部容
  • 应用Cryptopp库实现AES加密【转】

    crypto 自身的wiki上就有一些例子 可以参考 http www cryptopp com wiki Category Sample 本文来源 http ste xidian edu cn bbs a a asp B 5 ID 224
  • DirectX11学习笔记(不定期更新)

    目录 1 DX与HLSL的矩阵 2 创建常量缓冲区的尺寸需要按照16字节对齐 1 DX与HLSL的矩阵 DX的矩阵 DirectX XMMATRIX 按照行主元优先存储 而HLSL的矩阵默认按照列主元优先存储 解决这个问题的方法有两种 1
  • 【STM32 x ESP8266】连接 MQTT 服务器(报文,附部分源码解析)

    MQTT 协议作为物联网非常重要的传输协议 如何使用它十分重要 如果有不理解的同学可以点击这里学习 这里只是简单介绍一下 同时这里附上MQTT 3 1 1协议中文版 pdf 的链接 对协议底层感兴趣的同学可以下载学习一下 同时下面的实现函数
  • Qt Q_UNUSED使用

    以前经常在程序里定义很多局部变量 如果没有使用 Qt Creator就会报 未引用的局部变量 警告 因为不影响程序 一开始也没管 但随着程序代码变多 警告变动还是有点烦 到今天才知道这个Qt的有个消除这个警告的宏 Q UNUSED int
  • Flink系统架构

    Flink 的运行时架构中 最重要的就是两大组件 作业管理器 JobManger 和任务管理器 TaskManager 对于一个提交执行的作业 JobManager 是真正意义上的 管理者 Master 负责管理调度 所以在不考虑高可用的情
  • 如何将java项目部署到Linux服务器上

    博主之前并没有操作过服务器 以及部署项目 记第一次操作心得 仅供参考 在服务器上已经有了mysql的五个rpm安装包 jdk的rpm tomcat的tar gz 博主找了其他的博文说是需要配置java环境但是博主并没有操作到这一步 安装包是

随机推荐

  • ThinkPad开机停留在boot menu界面、进不了系统的解决方法

    方法一 1 开机点击F1进入到bios界面 2 进入Security Secure Boot Disabled 如果不修改Secure boot选项为Disabled 在光驱引导时可能会出现报错 3 进入Startup UEFI Legac
  • C++57个入门知识点_37 虚函数的直接调用与间接调用(函数的调用分为直接调用和间接调用,间接调用是虚函数所具有的的性质;间接调用:运行期通过查找对象的虚表下标来调用函数的方法)

    前面两篇C 57个入门知识点 35 函数覆盖的概念1 函数覆盖条件 父子类继承关系 函数名 参数列表 返回值 调用约定必须相同 有virtual关键字 函数覆盖 类虚表中成员函数从继承自父类变为自己的 C 57个入门知识点 36 函数覆盖的
  • Android中的Loaders机制

    转自 http blog csdn net guoshaobei article details 17451647 Loaders机制在Android 3 0版本后引入 Loaders机制使一个Activity或者一个Fragment更加容
  • 职工管理系统(C++)

    职工管理系统有以下8个功能 增加职工信息 实现批量添加职工功能 将信息录入到文件中 职工信息为 职工编号 姓名 部门编号 显示职工信息 显示公司内部所有职工的信息 删除离职职工 按照编号删除指定的职工 修改职工信息 按照编号修改职工个人信息
  • python笔记-排序函数

    List排序 sort val list 1 7 3 9 5 6 val list sort sort 没有返回值 在原列表上排序 val list sort reverse True 逆序 print val list 使用sort 方法
  • IDEA启动tomcat控制台中文乱码问题

    IntelliJ IDEA是很多程序员必备且在业界被公认为最好的Java开发工具 有很多小伙伴在安装完IDEA并且tomcat之后 启动tomcat会出现控制台中文乱码问题 如下图所示 具体解决步骤 一 修改当前 Web 项目 Tomcat
  • 从用户页面获取作品列表

    最近web端更新比较频繁 所以搞了很多方案来应对更新问题 本文内容是其中一种方案 从用户主页的HTML响应内容中抽取user信息和作品列表数据 下图中出现的内容都是在html名为RENDER DATA的script标签中 以urlencod
  • spring与loc

    loc 是控制反转 是一个概念 当前比较流行的实现方式有两种 一种是依赖查找 第二就是依赖注入 依赖注入是目前最优秀的解耦方式 第一个小程序 所需的jar包 spring beans 4 2jar spring context 4 2 ja
  • 5折交叉验证_交叉验证:评估模型表现

    注明 本文章所有代码均来自scikit learn官方网站 在实际情况中 如果一个模型要上线 数据分析员需要反复调试模型 以防止模型仅在已知数据集的表现较好 在未知数据集上的表现较差 即要确保模型的泛化能力 它指机器学习对新鲜样本的适应能力
  • 重写或替换jar中的类或方法两种方式

    上一篇 还没毕业 我就进了HR的黑名单 目录 序言 重写jar的两种方式 第一种 第二种 序言 在某些特殊场景下 我们需要修改 jar 包中的某些类和方法 jar 我们没有修改权限 那么怎么重写里面的类和方法呢 本文教你两种常用的方法 分享
  • TortoiseGit SSH拉取GitLab代码

    ING 前述 Git获取远端代码的方式主要有两种https和SSH 这两种方式的主要区别在于 1 https url克隆会比较方便 复制https url然后到git Bash里面直接用clone命令克隆到本地就好了 但是每次fetch和p
  • 黑猫带你学eMMC协议第19篇:eMMC RPMB区域详解(重放保护内存块)

    1 前言 1 1 声明 本文依据eMMC JEDEC5 1 网络资料及个人工作经验整理而成 如有错误请留言 本文结合eMMC JEDEC5 1协议手册查看效果更佳 文章为个人辛苦整理 付费内容 禁止私自转载 1 2 内容提要 本文大约一万一
  • 2. Redis持久化、主从哨兵架构详解

    分布式缓存技术Redis 1 Redis持久化 1 1 RDB快照 snapshot 1 1 1 bgsave的写时复制 COW 机制 1 2 AOF append only file 1 2 1 AOF重写 1 3 Redis 4 0 混
  • flea-frame-db使用之基于EntityManager实现JPA分表的数据库操作【旧】

    基于EntityManager实现JPA分表的数据库操作 引言 1 EntityManager持久化操作 2 分表规则定义 3 分表操作实现 4 自测 4 1 新增数据 4 2 查询数据 4 3 更新数据 4 4 删除数据 更新 引言 本文
  • 在不影响线上服务情况下,删除大表数据表

    在不影响线上数据库服务情况下 如何删除数据库中的大表 分析 数据库中表涉及到db和os两个层面 1 db层面删表涉及到table cache的全局唯一锁 一旦数据表过大 会长时间占用全局为一锁 导致db卡死 2 os层面涉及到数据表物理文件
  • 伤腰的Python爬虫案例,零基础必备实战教程。

    前言 今天带大家采集一个二次元图片网站 里面漂亮的小姐姐层出不穷 图片的数据量也是比较大的 来一睹为快吧 开发环境介绍 python 3 6 pycharm requests parsel os 爬虫案例数据采集一般步骤 找数据对应的链接地
  • conan的学习与使用

    conan学习与使用 资源 官方地址 C C Open Source Package Manager conan io 重要概念 什么是包管理工具 包管理工具的主要作用是管理第三方依赖 也可以看成一个 轮子 工厂 每个人都可以上传自己造的
  • verdi显示数据

    在波形数据上点右键 2 s complement 就是大家计算机课上学的 补码 1 s complement 是课上讲的 反码 signed magnitude 最高位是符号位 0 正数 1 负数 低位是绝对值 另外 ncverilog v
  • FFmpeg命令行工具学习(五):FFmpeg 调整音视频播放速度

    转自 https www cnblogs com renhui p 10709074 html FFmpeg对音频 视频播放速度的调整的原理不一样 下面简单的说一下各自的原理及实现方式 一 调整视频速率 调整视频速率的原理为 修改视频的pt
  • QT之实现简陋聊天

    相关知识 QT 数据库 TCP IP Socket 1 登陆界面 包含登陆和注册两种功能 思路如下 难点 建立服务器和数据库 数据库保存数据 服务器与数据库产生联系 解决 数据库与服务器放在同一个类中 登陆和注册时 客户端与服务端连接 传输