• QT & C++笔记


    语法

    变量声明

    直接声明的变量, 其赋值操作会产生值拷贝, 例如

    QString b("some text");
    QString a(b);
    
    int a = 10;
    int b = a;
    

    对于QList, QMap容器, 赋值操作是值拷贝, 例如下面的b变量会得到一份a的拷贝.

    QStringList a({"aa", "bb", "cc"});
    QStringList b = a;
    

    需要注意的是, 如果QList<T> 里的T是自定义类型(结构体或者类), 这个类型必须实现深拷贝的构造方法, 否则使用QList::append() 方法赋值并非真正的值拷贝, 在append的对象跳出方法区后, 其内部的值会被回收. 对于无法实现深拷贝的类型, 应当使用 QList<T *> 的方式构造列表.

    对于可变对象列表结构, 可以使用指针值方式, 这种方式方便对单个对象进行修改和释放操作

    # recommended
    QList<ClazzType *> list;
    
    # not recommended
    QList<ClazzType> *list;
    

      

    变量生命周期

    直接使用赋值产生的变量, 因为其产生于栈区, 其生命周期仅在其所处的方法内, 当方法执行完毕, 这个变量会被自动回收.

    使用new产生的变量, 不会因为方法结束而被回收, 需要显式delete. 与上一条结合, 如果使用赋值产生的变量是一个复杂对象, 对象内部的成员指针变量使用new进行了赋值, 这个指针所指向的内存并不会因为方法结束而回收, 需要在对象的析构方法中显式delete. 

    构造/析构

    对于结构体和对象, 构造/析构方法结构是一样的, 对于复杂结构体和复杂对象, 需要层层编写对应的构造和析构方法. 对于指针变量, 一个好习惯是在构造时将其值赋值为0.

    如果结构体/对象内只有值变量, 构造和析构方法可以为空, 只要存在指针变量, 就需要写析构方法. 在析构方法中要避免忘记delete, 避免越界delete, 例如

    struct AccountObject {
        QString user;
        QString pass;
    
        AccountObject(){}
        AccountObject(const AccountObject& a) :
            user(a.user), pass(a.pass) {}
    };
    
    struct InboundHTTPConfigurationObject {
        int timeout;
        QList<struct AccountObject *> accounts;
        bool allowTransparent;
        int userLevel;
    
        InboundHTTPConfigurationObject(){}
        InboundHTTPConfigurationObject(const InboundHTTPConfigurationObject& a) :
            timeout(a.timeout), allowTransparent(a.allowTransparent), userLevel(a.userLevel) {
            foreach(AccountObject *dummy, a.accounts) {
                AccountObject *account = new AccountObject(*dummy);
                accounts.append(account);
            }
        }
        ~InboundHTTPConfigurationObject() {
            foreach(AccountObject *account, accounts) {
                delete account;
            }
        }
    };
    
    struct StreamSettingsObject {
        // "tcp" | "kcp" | "ws" | "http" | "domainsocket" | "quic"
        QString network;
        // "none" | "tls"
        QString security;
        struct SockoptObject *sockopt;
        struct TransportTlsObject *tlsSettings;
        struct TransportTcpObject *tcpSettings;
        struct TransportKcpObject *kcpSettings;
        struct TransportWebSocketObject *wsSettings;
        struct TransportHTTPObject *httpSettings;
        struct TransportDomainSocketObject *dsSettings;
        struct TransportQuicObject *quicSettings;
    
        StreamSettingsObject() : sockopt(0), tlsSettings(0), tcpSettings(0),
            kcpSettings(0), wsSettings(0), httpSettings(0), dsSettings(0), quicSettings(0) {}
    
        StreamSettingsObject(const StreamSettingsObject& a) :
            network(a.network), security(a.security), sockopt(0), tlsSettings(0), tcpSettings(0),
            kcpSettings(0), wsSettings(0), httpSettings(0), dsSettings(0), quicSettings(0) {
            if (a.sockopt) {
                sockopt = new SockoptObject(*(a.sockopt));
            }
            if (a.tlsSettings) {
                tlsSettings = new TransportTlsObject(*(a.tlsSettings));
            }
            if (a.tcpSettings) {
                tcpSettings = new TransportTcpObject(*(a.tcpSettings));
            }
            if (a.kcpSettings) {
                kcpSettings = new TransportKcpObject(*(a.kcpSettings));
            }
            if (a.wsSettings) {
                wsSettings = new TransportWebSocketObject(*(a.wsSettings));
            }
            if (a.httpSettings) {
                httpSettings = new TransportHTTPObject(*(a.httpSettings));
            }
            if (a.dsSettings) {
                dsSettings = new TransportDomainSocketObject(*(a.dsSettings));
            }
            if (a.quicSettings) {
                quicSettings = new TransportQuicObject(*(a.quicSettings));
            }
        }
    
        ~StreamSettingsObject() {
            if (sockopt) delete sockopt;
            if (tlsSettings) delete tlsSettings;
            if (tcpSettings) delete tcpSettings;
            if (kcpSettings) delete kcpSettings;
            if (wsSettings) delete wsSettings;
            if (httpSettings) delete httpSettings;
            if (dsSettings) delete dsSettings;
            if (quicSettings) delete quicSettings;
        }
    };
    

    深拷贝

    对于深拷贝, 可以用方法实现, 也可以直接使用构造函数, 可以参考上面的代码例子.

    函数参数的类型

    1. 值传递 func(ClazzType param) 此时会进行变量复制,在函数内部看到的param与外部调用时使用的param不是同一个对象。

    2. 传递指针 func(ClazzType *param) 这时候传递的是param这个指针自身的值,在函数内部可以对指针所指向的ClazzType实例进行修改。

    3. 传递引用 func(ClazzType &param) 此时传递的是param这个对象自身,避免了func(ClazzType param) 这种形式下的值复制,在函数内部修改param,等同于在外部直接修改。一种特殊用法就是在对象的构造函数中 ClazzType(const ClazzType& param), 避免变量复制,更加高效。

    4. 返回引用 ClazzType& func(params... ) 这种函数返回的变量,必须是在函数外已经声明的变量,这种方式的好处是避免变量复制,不会产生返回值的副本。

    关键词

    const

    explicit 在构造函数上使用此关键词,用于避免在类型对比时使用错误的隐式转换,

    static 静态变量和静态方法

    inline 内联方法将在编译时直接展开到调用处,但是是否使用内联是由编译器来决定的

  • 相关阅读:
    分享24款非常有用的 jQuery 插件
    分享30个最佳WordPress电子商务主题
    使用 CSS3 可以实现的五种很酷很炫的效果
    记录一些常用的python库、软件或者网址
    树的遍历
    深度优先遍历怎么抓住小偷
    hash算法的应用
    mysql的一些常用操作(一)
    Serverless 2.0,鸡蛋还是银弹?
    基于 KubeVela 与 Kubernetes 打造“无限能力”的开放 PaaS
  • 原文地址:https://www.cnblogs.com/milton/p/12964848.html
Copyright © 2020-2023  润新知