【C->Cpp】由C迈向Cpp(4)

本文介绍了C++中的内联函数、关键字auto的自动类型推断功能、范围for的便捷语法以及nullptr的使用,探讨了这些特性如何优化代码并提升编译效率。
摘要由CSDN通过智能技术生成


目录

(一)内联函数

 (二)关键字auto

 (三)范围for

 (四)nullptr


正文开始:

(一)内联函数

宏定义:

        C++的内联函数是在C语言宏的基础上提出的,C语言宏是一种预处理器指令,用于在编译过程中进行文本替换。宏定义可以用来定义常量、函数、条件语句等,它们在程序编译之前被  替换  为相应的代码。

        宏定义使用#define关键字,语法格式为:

#define 宏名 字符串

        宏名通常使用大写字母表示,字符串可以是任意有效的C语言代码。宏定义的作用范围为宏定义之后直到文件末尾或者遇到  #undef  指令。  宏名称在程序中会被替换为对应的字符串,这个替换过程是在编译之前由预处理器完成的。

宏函数:

        宏定义还可以带有参数,类似于函数,可以根据参数的不同生成不同的代码。宏参数使用括号括起来,并且在宏定义中用逗号隔开。例如:

#define  MAX(x, y) ((x) > (y) ? (x) : (y))

这个宏定义了一个求两个数中较大值的函数,它可以像函数一样调用:

int max = MAX(a, b);

在编译过程中,预处理器会将MAX(a, b)替换为((a) > (b) ? (a) : (b)),然后再进行编译。

 条件宏:

        宏定义还可以使用条件语句,例如:

#define DEBUG

#ifdef DEBUG printf("Debugging is enabled\n"); #endif

        在编译过程中,如果宏定义了DEBUG,那么条件编译指令#ifdef DEBUG和#endif之间的代码会被编译,否则会被忽略。

         宏的缺点是非常明显的,以加法宏函数为例,想要正确写出宏函数,需要考虑:

#define  ADD(x,y)  ((x)+(y))

(1)为什么要加内层括号?

        对于一些情况比如x,y是运算符优先级低于加法运算符优先级的情况,如果不加内层括号,就会在算出x,y结果之前进行+运算。

(2)为什么要加外层括号?

        在ADD(8,9)*8情况下,如果不加括号,进行宏替换后就会先运算9*8,而不是先算出ADD的结果再进行运算。

(3)宏定义末尾不能加分号?

        在对ADD函数进行嵌套调用的时候,如果加上末尾的“;”,就会出现多余分号的情况。

        C语言中的宏定义提供了一种在编译前进行代码替换的机制,它可以提高代码的灵活性和可重用性。但是宏定义也有一些缺点,如代码可读性差(导致调试不方便)、与函数相比没有类型检查(宏做的仅仅是替换),在有些场景下比较复杂(需要谨慎替换后运算符的优先级)等。因此,在使用宏定义时需要谨慎考虑代码的可读性和可维护性。

        由于宏的缺点比较明显,于是C++推荐:

        i, 用const和enum替代宏常量;

        ii,用inline(内联函数)替代宏函数;

 C++的替代

        宏常量可以牵一发而动全身,提高代码的可维护性;宏函数可以不用建立函数栈帧,提高了效率;

内联函数

//内联函数的写法
inline Add(int x,int y)
{
    return x+y;
}

int main()
{
    std::cout << Add(6,5) << std::endl;

    return 0;
}

特性:

        内联函数是以空间换时间的做法,如果编译器将函数当成内联函数处理,会在编译阶段,用函数体替换函数调用;

        缺陷:可能会使编译后的文件(可执行程序)变大;

        优点:减少了调用开销,提高了程序运行效率;

        

        内联函数是对编译器的一个建议,对于我们实现的内联函数,编译器不一定执行,不同编译器关于inline函数得实现机制可能不同;一般情况下,建议将函数规模较小,不是递归且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性;

        inline函数不要让声明和定义分离,分离会导致链接错误;因为inline被展开,就不再调用函数,没有函数地址了,链接就会找不到。

 (二)关键字auto

        在C++中,关键字auto用于声明一种自动类型推断的变量。它允许编译器根据变量的初始值来推断变量的类型,并将其类型作为变量的类型。

        使用auto关键字可以简化代码,减少类型声明的冗余,并提高代码的可读性。

int a = 10;
auto b = a;//自动推断b的类型为int

         auto关键字被用于声明变量b,并根据它们的初始值来推断其类型。

auto x = 10; // x的类型被推断为int
auto str = "Hello"; // str的类型被推断为const char *

        auto关键字被用于声明变量x和str,并根据它们的初始值来推断其类型。

        迭代器类型推导:

        auto关键字可以在C++11及以后的版本中用于自动推导迭代器类型。

std::vector<int> numbers = {1, 2, 3, 4, 5}; 

for(auto it = numbers.begin(); it != numbers.end(); ++it) 
{
     std::cout << *it << " "; 
}

        在上面的例子中,auto关键字用于推导迭代器it的类型,编译器会根据numbers容器的类型推导出it的类型为std::vector<int>::iterator(这样就简化了输入类型的代码)。

auto特性: 

        需要注意的是,auto关键字在类型推导时会考虑初始化值,所以在使用auto声明变量时,要确保初始化值是明确的,否则推导的结果可能不符合预期。

        auto不能作为函数形参的类型推导;

        auto不能直接用来声明数组;

        在一行声明多个变量时,变量的推断类型必须一致;

auto a = 5,b = 6;    //推断为int
auto a = 5,b = 6.0;  //推断声明失败

 (三)范围for

         C++11中新增的语法,便利数组,新增了范围for的用法:

int arr[] = {1,2,3,4,5};

for(auto i : arr )
{
    cout << i << endl;
}
int arr[] = {1,2,3,4,5};

for(int i  = 0; i < sizeof(arr)/sizeof(int);i++ )
{
    cout << arr[i] << endl;
}

        上述两种遍历数组的结果是一样的;

        对于范围for,编译器自动识别数组中的数据类型并赋值给i对象,自动判断结束;

范围for特性:

         e的改变并不会改变数组元素的值:

int arr[] = {1,2,3,4,5};

for(auto i : arr)//e的改变并不影响数组的元素的值
{
    e*=2;
    cout << e << endl;
}

        不能在数组传参的函数内使用,数组传参本质上是传递数组首元素的地址;

 (四)nullptr

         C++中如果NULL作为函数参数进行函数重载,会被默认识别成  整型0 ,但是NULL本质上是(void*)0  ;

        于是C++11打了一个补丁,用nullptr替代NULL,nullptr会被识别为(void*)0;

        nullptr是一个关键字;

        (为了向前兼容,C++没有直接将NULL的定义改为(void*)0)


完~

未经作者同意禁止转载

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
#include "mylogin.h" mylogin::mylogin(QWidget *parent) : QDialog(parent) { this->init_ui(); connect(this->bnt_login, &QPushButton::clicked, this, &mylogin::do_login); connect(this->bnt_register, &QPushButton::clicked , this ,&mylogin::do_enroll); } mylogin::~mylogin() { } void mylogin::init_ui() { this->setFixedSize(QSize(600,350)); this->setWindowTitle(tr("岑超升")); this->setWindowIcon(QIcon(":/src/1.png")); this->lb1 = new QLabel(); this->lb2 = new QLabel(); this->lb3 = new QLabel(); this->lb1->setFixedSize(QSize(560,200)); QPixmap pic; pic.load(":/src/2.png"); //this->lb1->setPixmap(pic.scaled(this->lb1->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); this->lb1->setPixmap(QPixmap(":/src/2.png")); this->lb2->setText(tr("用户名:")); this->lb3->setText(tr("密 码:")); this->usr_name_le = new QLineEdit(); //这两个参数后面传入信号中去,然后emit发射出去 this->usr_pass_le = new QLineEdit(); this->usr_pass_le->setEchoMode(QLineEdit::Password); this->bnt_login = new QPushButton(tr("登 陆")); this->bnt_register = new QPushButton(tr("注 册")); this->hb1 = new QHBoxLayout(); this->hb2 = new QHBoxLayout(); this->hb3 = new QHBoxLayout(); this->hb1->addWidget(this->lb2); this->hb1->addWidget(this->usr_name_le); this->hb2->addWidget(this->lb3); this->hb2->addWidget(this->usr_pass_le); this->hb3->addWidget(this->bnt_login); this->hb3->addWidget(this->bnt_register); this->vb1 = new QVBoxLayout(); this->vb1->addWidget(this->lb1); this->vb1->addLayout(this->hb1); this->vb1->addLayout(this->hb2); this->vb1->addLayout(this->hb3); this->setLayout(this->vb1); } void mylogin::do_login() { emit sig_login(usr_name_le->text(), usr_pass_le->text()); //需要把这里输入的账号密码信息发送到myapp那去,用到的函数是emit //需要自定义一个信号,sig_login //这个槽函数能够发出信号 } void mylogin::do_enroll() { emit sig_enroll(); }用C++语言解释并注释每行代码的语法
06-09
这段代码是一个 Qt 程序,用于实现一个登录界面。 ```cpp #include "mylogin.h" ``` 包含一个名为 "mylogin.h" 的头文件。 ```cpp mylogin::mylogin(QWidget *parent) : QDialog(parent) { ``` 定义了一个名为 mylogin 的类,并继承自 QDialog 类。在构造函数中使用了成员初始化列表,将 parent 传递给 QDialog 的构造函数。 ```cpp this->init_ui(); ``` 调用了 init_ui 函数,用于初始化界面。 ```cpp connect(this->bnt_login, &QPushButton::clicked, this, &mylogin::do_login); connect(this->bnt_register, &QPushButton::clicked , this ,&mylogin::do_enroll); ``` 使用 connect 函数将两个按钮的 clicked 信号连接到两个槽函数,分别是 do_login 和 do_enroll。 ```cpp mylogin::~mylogin() { ``` 析构函数。没有实现具体的逻辑,因为这个类中没有需要手动释放的资源。 ```cpp void mylogin::init_ui() { ``` 初始化界面的函数。 ```cpp this->setFixedSize(QSize(600,350)); ``` 设置窗口大小为 600x350。 ```cpp this->setWindowTitle(tr("岑超升")); ``` 设置窗口标题为 “岑超升”。 ```cpp this->setWindowIcon(QIcon(":/src/1.png")); ``` 设置窗口图标为 “1.png”。 ```cpp this->lb1 = new QLabel(); this->lb2 = new QLabel(); this->lb3 = new QLabel(); ``` 定义了三个 QLabel 对象。 ```cpp this->lb1->setFixedSize(QSize(560,200)); ``` 设置第一个 QLabel 的固定大小为 560x200。 ```cpp QPixmap pic; pic.load(":/src/2.png"); //this->lb1->setPixmap(pic.scaled(this->lb1->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); this->lb1->setPixmap(QPixmap(":/src/2.png")); ``` 定义了一个 QPixmap 对象 pic,加载了 “2.png” 图片。然后将这个图片设置为第一个 QLabel 的背景图片。 ```cpp this->lb2->setText(tr("用户名:")); this->lb3->setText(tr("密 码:")); ``` 设置第二个和第三个 QLabel 的文本内容。 ```cpp this->usr_name_le = new QLineEdit(); this->usr_pass_le = new QLineEdit(); this->usr_pass_le->setEchoMode(QLineEdit::Password); ``` 定义了两个 QLineEdit 对象,分别用于输入用户名和密码。将密码框的 echoMode 设置为 Password,以保证输入的内容不可见。 ```cpp this->bnt_login = new QPushButton(tr("登 陆")); this->bnt_register = new QPushButton(tr("注 册")); ``` 定义了两个 QPushButton 对象,分别用于登录和注册。 ```cpp this->hb1 = new QHBoxLayout(); this->hb2 = new QHBoxLayout(); this->hb3 = new QHBoxLayout(); this->hb1->addWidget(this->lb2); this->hb1->addWidget(this->usr_name_le); this->hb2->addWidget(this->lb3); this->hb2->addWidget(this->usr_pass_le); this->hb3->addWidget(this->bnt_login); this->hb3->addWidget(this->bnt_register); ``` 定义了三个 QHBoxLayout 对象,分别用于放置用户名、密码和登录、注册两个部分。将 QLabel 和 QLineEdit、QPushButton 对象添加到对应的 QHBoxLayout 中。 ```cpp this->vb1 = new QVBoxLayout(); this->vb1->addWidget(this->lb1); this->vb1->addLayout(this->hb1); this->vb1->addLayout(this->hb2); this->vb1->addLayout(this->hb3); this->setLayout(this->vb1); ``` 定义了一个 QVBoxLayout 对象,用于放置整个界面的内容。将三个 QHBoxLayout 添加到 QVBoxLayout 中,然后将 QVBoxLayout 设置为当前窗口的布局。 ```cpp void mylogin::do_login() { emit sig_login(usr_name_le->text(), usr_pass_le->text()); } ``` 定义了一个槽函数 do_login,当用户点击登录按钮时,会发射一个 sig_login 信号,并将输入的用户名和密码作为参数传递给信号。 ```cpp void mylogin::do_enroll() { emit sig_enroll(); } ``` 定义了一个槽函数 do_enroll,当用户点击注册按钮时,会发射一个 sig_enroll 信号。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水墨不写bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值