【学习日志】2022.11.10 C++11常量表达式、用户定义字面量、原生字符串字面值、类的改进、Leetcode疼迅优选50提T1

常量表达式

常量表达式主要是允许一些计算发生在编译时,即发生在代码编译而不是运行的时候。

这是很大的优化:假如有些事情可以在编译时做,它将只做一次,而不是每次程序运行时都计算。

使用constexpr,你可以创建一个编译时的函数:

constexpr int GetConst()
{
    return 3;
}

int main()
{
    int arr[ GetConst() ] = {0};
    enum { e1 = GetConst(), e2 };

    constexpr int num = GetConst();

    return 0;
}

constexpr函数的限制:

  1. 函数中只能有一个return语句(有极少特例)
  2. 函数必须返回值(不能是void函数)
  3. 在使用前必须已有定义
  4. return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式
//err,函数中只能有一个return语句
constexpr int data()
{
    constexpr int i = 1;
    return i;
}

constexpr int data2()
{
    //一个constexpr函数,只允许包含一行可执行代码
    //但允许包含typedef、 using 指令、静态断言等。
    static_assert(1, "fail");
    return 100;
}

int a = 3;
constexpr int data3()
{
    return a;//err, return返回语句表达式中不能使用非常量表达式的函数、全局数据
}

int main()
{
    constexpr int func(); //函数声明,定义放在main函数后面
    constexpr int c = func();  //err, 无法通过编译, 在使用前必须已有定义

    return 0;
}

constexpr int func()
{
    return 1;
}

常量表达式的构造函数有以下限制:

  1. 函数体必须为空
  2. 初始化列表只能由常量表达式来赋值
struct Date
{
    constexpr Date(int y, int m, int d): year(y), month(m), day(d) {}

    constexpr int GetYear() { return year; }
    constexpr int GetMonth() { return month; }
    constexpr int GetDay() { return day; }

private:
    int year;
    int month;
    int day;
};

int main()
{
    constexpr Date PRCfound {1949, 10, 1};
    constexpr int foundmonth = PRCfound.GetMonth();

    cout << foundmonth << endl;  // 10

    return 0;
}

用户定义字面量

用户自定义字面值,或者叫“自定义后缀”更直观些,主要作用是简化代码的读写。

long double operator"" _mm(long double x) { return x / 1000; }
long double operator"" _m(long double x)  { return x; }
long double operator"" _km(long double x) { return x * 1000; }

int main()
{
    cout << 1.0_mm << endl; //0.001
    cout << 1.0_m  << endl; //1
    cout << 1.0_km << endl; //1000

    return 0;
}

根据 C++ 11 标准,只有下面参数列表才是合法的:

char const *
unsigned long long
long double
char const *, size_t
wchar_t const *, size_t
char16_t const *, size_t
char32_t const *, size_t

size_t operator"" _len(char const * str, size_t size)
{
    return size;
}

int main()
{
    cout << "mike"_len <<endl; //结果为4

    return 0;
}

char const * operator"" _r(char const* str)
{
    return str;
}

int main()
{
    cout << 250_r <<endl; //结果为250

    return 0;
}

原生字符串字面值

原生字符串字面值(raw string literal)使用户书写的字符串“所见即所得”。C++11中原生字符串的声明相当简单,只需在字符串前加入前缀,即字母R,并在引号中使用括号左右标识,就可以声明该字符串字面量为原生字符串了。

int main()
{
    cout << R"(hello,\n
         world)" << endl;

    return 0;
}

类的改进

继承构造

C++ 11允许派生类继承基类的构造函数(默认构造函数、复制构造函数、移动构造函数除外)。

class A
{
public:
    A(int i) { cout << "i = " << i << endl; }
    A(double d, int i) {}
    A(float f, int i, const char* c) {}
    // ...
};

class B : public A
{
public:
    using A::A; // 继承构造函数
    // ...
    virtual void ExtraInterface(){}
};

委托构造

和继承构造函数类似,委托构造函数也是C++11中对C++的构造函数的一项改进,其目的也是为了减少程序员书写构造函数的时间。

如果一个类包含多个构造函数,C++ 11允许在一个构造函数中的定义中使用另一个构造函数,但这必须通过初始化列表进行操作,如下:

class Info
{
public:
    Info() : Info(1) { }    // 委托构造函数
    Info(int i) : Info(i, 'a') { } // 既是目标构造函数,也是委托构造函数
    Info(char e): Info(1, e) { }

private:
    Info(int i, char e): type(i), name(e) { /* 其它初始化 */ } // 目标构造函数
    int  type;
    char name;
    // ...
};

继承控制:final和override

class B1 final {}; // 此类不能被继承
//class D1: public B1 {}; // error!

class B
{
public:
//  virtual void func() override // error! 指定了重写但实际并没重写,没有基类
//  {
//      cout << __func__ << std::endl;
//  }
    virtual void f() const
    {
        cout << __func__ << std::endl;
    }
    virtual void fun()
    {
        cout << __func__ << std::endl;
    }
};

class D : public B
{
public:
    virtual void f(int)      // ok! 隐藏,由于没有重写同名函数B::f,在D中变为不可见
    {
        cout << "hiding: " <<__func__ << std::endl;
    }
//  virtual void f() override   // error! 指定了重写但实际并没重写,类型声明不完全相同
//  {
//      cout << __func__ << std::endl;
//  }
    virtual void fun() override final // ok! 指定了重写实际上也重写了,同时,指定为最终,后代类中不能再重写此虚函数
    {
        cout << __func__ << std::endl;
    }
};

class D2 : public D
{
public:
    virtual void f() const      // ok! 重写B::f(),同时,由于没有重写D::f(int),在D2中变不可见
    {
        cout << __func__ << std::endl;
    }
//  virtual void fun() // error! 基类的此虚函数被指定为最终,不能被重写,虽然没有显示指定"override"
//  {
//      cout << __func__ << std::endl;
//  }
//  virtual void fun() override // error! 基类的此虚函数被指定为最终,不能被重写
//  {
//      cout << __func__ << std::endl;
//  }
};

Leetcode疼迅优选50提T1

ListNode两数相加

ListNode_码盲进化路的博客-CSDN博客_listnode代码】ListNode。https://blog.csdn.net/qq_38494269/article/details/126004648?ops_request_misc=&request_id=&biz_id=102&utm_term=listnode&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-126004648.142^v63^control_1,201^v3^add_ask,213^v2^t3_control1我所知道的链表(下)_上山抓鱼的博客-CSDN博客双链表的删除插入操作、循环链表的插入删除。单链表的反转、合并操作。https://blog.csdn.net/FisherandPiger/article/details/126236579?ops_request_misc=&request_id=&biz_id=102&utm_term=%20temp%20=%20cur%20-%3E%20next;%20%20%20%20%20%20%20%20%20%20&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-126236579.142^v63^control_1,201^v3^add_ask,213^v2^t3_control1链表相关(设计链表及环链表问题)_weixin_46213145的博客-CSDN博客_while(cur->next)双向链表的设计 包括删除添加节点等操作 链表的翻转等https://blog.csdn.net/weixin_46213145/article/details/125899898?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166808415016800186581900%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166808415016800186581900&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-125899898-null-null.142^v63^control_1,201^v3^add_ask,213^v2^t3_control1&utm_term=%20temp%20%3D%20cur%20-%3E%20next%3B%20%20%20%20%20%20%20%20%20%20%20%20%20cur-%3Enext%20%3D%20pre%3B列表(ListNode)_hurricane&&storming的博客-CSDN博客_listnodeListNode列表节点 ADT 支持的操作接口操作接口功能data()当前节点所存数据对象pred()当前节点前驱节点的位置succ()当前节点后继节点的位置insertAsPred(e)插入前驱节点,存入被引用对象 e,返回新节点位置insertAsSucc(e)插入后继节点,存入被引用对象 e,返回新节点的位置列表 ADT 支持的操作接口操作接口功能适用对象size()返回节点总数列表first()、lahttps://blog.csdn.net/weixin_48033173/article/details/113035785?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166808175016782412568745%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166808175016782412568745&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-113035785-null-null.142^v63^control_1,201^v3^add_ask,213^v2^t3_control1&utm_term=listnode

cpp

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head = nullptr, *tail = nullptr;
        int carry = 0;
        while (l1 || l2) {
            int n1 = l1 ? l1->val: 0;
            int n2 = l2 ? l2->val: 0;
            int sum = n1 + n2 + carry;
            if (!head) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail->next = new ListNode(sum % 10);
                tail = tail->next;
            }
            carry = sum / 10;
            if (l1) {
                l1 = l1->next;
            }
            if (l2) {
                l2 = l2->next;
            }
        }
        if (carry > 0) {
            tail->next = new ListNode(carry);
        }
        return head;
    }
};

c#

public class Solution {
    public ListNode AddTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null, tail = null;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            int sum = n1 + n2 + carry;
            if (head == null) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            carry = sum / 10;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry > 0) {
            tail.next = new ListNode(carry);
        }
        return head;
    }
}

猜你喜欢

转载自blog.csdn.net/Angelloveyatou/article/details/127787727