前言
众所周知, 相较于其他各种有包管理的语言,c 的开发难度直线飙升,而且各种新的语言特性还层出不穷,不但没有降低语法难度还增加了,所以人生苦短,我用 xxx 成了学 c 的几乎必然吐槽的事情。
这里也就写几篇文章记录一下 c 语法特性,主要是为了放松,争取写出 epoll 和那个大名鼎鼎的 reactor 模型。
今天就轻松一点,写几个 c 11 语法特性。
类型推断
类型推断很简单,就是根据你的表现推断你是什么类型,这跟 golang python 语言很像了。语法也较为简单,有两种分别是 auto , decltype。写一个简单代码验证。
代码语言:c 复制#include <iostream>
using namespace std;
int main()
{
auto var1 = 250;
decltype(199.88) var2;
cout << "var1占据字节个数:" << sizeof(var1) << endl;
cout << "var2占据字节个数:" << sizeof(var2) << endl;
return 0;
}
注意上述结果在不同编译器和平台上可能会有区别,这里主要表现其推断功能,其中第一个推断成 int, 第二个推断出 double。
序列 for 循环
for each 这个语言特性在很多语言中都有,例如 Java, python 等等,很不幸,c 也引入了这个特性。
代码语言:c 复制#include <iostream>
using namespace std;
int main()
{
for (const auto var : { 54,67,90,12,53,88,77,123,54,20 })
cout << var << " ";
cout << endl<<endl;
for (const auto str : { "ABC","DEF","GHI","JKL" })
cout << str << " ";
cout << endl;
return 0;
}
lamda 表达式
这个表达式跟其他语言其实也有部分不同,不过限于篇幅就不做横向对比了,其常见格式是:
代码语言:c 复制[](a, b){逻辑}
其中 表示数组或者 vector 元素,然后a,b是其中参数,大括号中是参数逻辑,可以比较,输出到控制台等等。
代码语言:c 复制#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool comparefunc(int x, int y)
{
return x < y;
}
int main()
{
vector<int> myvr{ 93,78,133,21,89 };
vector<int> lvec{8,3,5,2,1};
// 平时常用的方法如下
sort(myvr.begin(), myvr.end(), comparefunc);
cout << "常用输出结果为:" << endl;
for (int it : myvr)
cout << it << ' ';
cout << endl;
// 下面我们使用lambda表达式
sort(lvec.begin(), lvec.end(), [](int a, int b)->bool {return a < b; });
cout << "lambda表达式输出结果为:" << endl;
for (int il : lvec)
cout << il << ' ';
cout << endl;
return 0;
}
这里用两种方式做了对比,如果觉得 lamda 表达式别扭可以不使用,他只是让代码看起来优雅,但是实际工程以不出错为优先,然后再是优雅。
委托构造函数
委托构造函数是当一个类中有多个构造函数为了避免代码重复的一种写法,还是那句话,有些语言特性属于可以但没必要,我们可以用这个创造 kpi,但是实际工程代码丑一点也可以可以接受的。
代码语言:c 复制#include <iostream>
#include <string>
using namespace std;
// 创建一个类
class TestC
{
public:
// 普通构造函数
TestC(string s, int d) :_data(d), _str(s)
{
cout << "程序执行:普通构造函数的函数体" << endl;
}
// 委托构造函数
TestC(int d) :TestC("测试TestC(int d)", d)
{
cout << "程序执行:委托构造函数TestC(int d) 的函数体" << endl;
}
void printdata()const
{
cout << "-------------------------------------" << endl;
cout << "_str=" << _str << endl;
cout << "_data=" << _data << endl;
cout << "-------------------------------------" << endl << endl;
}
private:
int _data;
string _str;
};
int main()
{
TestC objc1("测试普通构造函数:TestC(string s, int d) ", 250);
objc1.printdata();
TestC objc2(890);
objc2.printdata();
return 0;
}
这个可能有点不好理解,就是我有两个参数构造函数又有一个参数构造函数,所以为了写代码方便一点,就在第二个函数构造委托给了第一个构造函数。
上述代码执行结果如下:
可以看到,委托构造函数构造过程会先构造其委托的构造函数,然后再构造自己对象。相当于先构造了一个多参数对象,然后将其中某几个自己构造参数更改为自己传入的参数的值。
垃圾回收机制
这个明显不是语言特性,但是有必要聊一聊,c 本身没有垃圾回收机制,所有就需要自己进行垃圾回收,因此有了一对 new/delete malloc/free 这样组合。
当然对于 c 类来说,其对象创建可以分为在堆上创建和在栈上创建,在栈上创建不需要垃圾回收,在堆上则需要。
代码语言:c 复制#include <iostream>
// 定义一个简单的类
class MyClass {
private:
int myNumber; // 私有成员变量
public:
// 构造函数,用于初始化对象
MyClass(int num) {
myNumber = num;
}
// 成员函数,打印成员变量的值
void printNumber() {
std::cout << "My number is: " << myNumber << std::endl;
}
// 成员函数,设置成员变量的值
void setNumber(int num) {
myNumber = num;
}
};
int main() {
// 创建一个 MyClass 对象
MyClass obj(42);
// 调用成员函数打印对象的成员变量值
obj.printNumber();
// 修改成员变量的值并再次打印
obj.setNumber(100);
obj.printNumber();
return 0;
}
上述对象就是在栈上创建的,不需要垃圾回收。
代码语言:c 复制int main() {
// 在堆上创建一个 MyClass 对象
MyClass* obj_ptr = new MyClass(42);
// 使用箭头运算符(->)来访问对象的成员函数
obj_ptr->printNumber();
// 修改成员变量的值并再次打印
obj_ptr->setNumber(100);
obj_ptr->printNumber();
// 在不需要对象时,记得释放堆上分配的内存
delete obj_ptr;
return 0;
}
这个对象就是在堆上创建的,需要 delete 进行垃圾回收。
正则表达式
正则表达式不多说,直接上代码。
代码语言:c 复制#include <iostream>
#include <string>
#include <regex>
int main()
{
std::regex string_reg("[1-9](\d{5,11})"); //匹配规则
std::string strtest("1032111"); //测试字符
std::smatch matchresults; //匹配结构,如果匹配会返回两个内容,一个是测试字符,另一个是匹配上的字符。
// 正则匹配
if (std::regex_match(strtest, matchresults, string_reg))
{
std::cout << "Match:" << std::endl;
// 输出表达式结果
for (size_t i = 0; i < matchresults.size(); i )
{
std::cout << matchresults[i] << std::endl;
}
}
else
{
std::cout << "Not Match:" << std::endl;
}
return 0;
}
上述代码较为简单,直接上结果。
constexpr
就是常量表达式, const 表示常量,而这个就是一个表达式是常量,他不会变,不然会报错,因为使用较为简单,就不举例子了。
基本语言特性就到这里了,语言特性重要但是有没有那么重要,编程思维才是最重要的。