常量表达式
常量表达式主要是允许一些计算发生在编译时,即发生在代码编译而不是运行的时候。
这是很大的优化:假如有些事情可以在编译时做,它将只做一次,而不是每次程序运行时都计算。
使用constexpr,你可以创建一个编译时的函数:
constexpr int GetConst()
{
return 3;
}
int main()
{
int arr[ GetConst() ] = {0};
enum { e1 = GetConst(), e2 };
constexpr int num = GetConst();
return 0;
}
constexpr函数的限制:
- 函数中只能有一个return语句(有极少特例)
- 函数必须返回值(不能是void函数)
- 在使用前必须已有定义
- 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;
}
常量表达式的构造函数有以下限制:
- 函数体必须为空
- 初始化列表只能由常量表达式来赋值
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;
}
}