意想不到的宏操作

目录

 

意想不到的宏操作

大家熟知的#define

预定义常量:普通的文本替换

预定义简单函数

学会使用宏函数assert()来纠错

Assert函数使用的基本方法

不为人知的#define,#ifndef,#ifdef,#endif的妙用


意想不到的宏操作

大家熟知的#define

预定义常量:普通的文本替换

在预处理阶段定义的常量,无法规定他的返回值类型,返回什么完全依赖于输入,这对程序提出了严峻的考验,因此,我们要尽可能地避免用预定义的方式定义常量,这很快但不安全(这里的安全指“数据类型安全”)。

预定义简单函数

#include <iostream>  
using namespace std;  
  
#define PI 3.1415926  
#define AREA(r) (PI*(r)*(r))  
  
int main()  
{  
    cout << AREA(3.2+2.4) << endl;  
}  
// 输出结果为98.5203

 

大家思考一下,为什么用预定义的方式定义函数一定要加那么多()括号呢?

我们不加括号试试:

#include <iostream>  
using namespace std;  
  
#define PI 3.1415926  
#define AREA(r) (PI*r*r)  
  
int main()  
{  
    cout << AREA(3.2 + 2.4) << endl;  
}  
// 输出结果为20.1331

 

为什么呢?

这里就要考虑运算符优先级的问题了!20.1331=PI*3.2+2.4*3.2+3.2,这里“乘法优先于加法”。

为了解决这个问题,我们要加括号来解决默认的运算符优先级:

#define AREA PI*(r)*(r).

学会使用宏函数assert()来纠错

Assert函数使用的基本方法

针对于指针

当assert(logical expression)中的逻辑表达式logical expression返回值为true时,系统会自动报错,并且如果你想使用assert函数,必须添加assert.h头文件。

#include <assert.h>  
  
int main()  
{  
    char* sayHello = NULL;  
// 使用形式为:assert(pointer),当pointer==null时,触发错误提示
    assert(sayHello); // 会自动报错,并且显示出第几行满足错误成立条件,即指针==null  
    delete[] sayHello;      
    return 0;  
}  

 

输出错误提示:

 

代码错误位置提醒:

 

但是注意:

Assert在代码发布时,不可用,编译不通过,因为发布的代码是已经调试过的,满足安全,性能需求的,再加上那么多调试程序岂不是太过冗杂。但是如果你想在任何时候都可以编译通过,可以用if判断语句来实现纠错功能。由此可见,assert宏函数仅仅是为了提示错误位置提高纠错效率而使用的,如果像满足错误之后,输出更多的信息,那必须选择if语句。

针对于普通变量

assert(varable >= 0); // 满足条件,逻辑表达式返回true,就会触发错误警告

注意:assert()不可以执行任何改变变量的指令

assert仅供错误判断,不能执行任何程序,例如:assert(++i>100),其中i的值发生改变,编译器会报错!

不为人知的#define,#ifndef,#ifdef,#endif的妙用

当我们在类A中调用类B,在类B中调用类A,会出现什么错误呢?

当我们不加限制,A->B->A->B->……无限制嵌套下去,这既是死循环,是无解的。

那如何避免呢?

我们可以用宏操作来在预编译阶段就对于这种问题加以规范。

① Cstudent.h文件

#pragma once  
  
#include <string>  
using namespace std;  
  
#ifndef Cstudent_H  
#define Cstudent_H  
class Cteacher; // 声明一下Cteacher类  
class Cstudent  
{  
private:  
    string Sname;  
    string Sposition;  
    int Sage;  
public:  
    Cteacher *teacher;  
public:  
    Cstudent(string name, string position, int age);  
    ~Cstudent();  
    void ShowTeacherInf();  
    string ReturnName();  
};  
#endif  

 

② Cteacher.h文件

#pragma once  
  
#include <string>  
using namespace std;  
  
#ifndef Cteacher_H  
#define Cteacher_H  
class Cstudent;  
class Cteacher  
{  
private:  
    string Tposition;  
    string Tname;  
    int Tage;  
public:  
    Cstudent *stud; // 未声明类体的类可以定义指针,但绝对不可以定义变量,因为没有实体,系统不知道内存怎么分配  
public:  
    Cteacher(string Tname, string Tposition, int Tage);  
    ~Cteacher();  
    void ShowStudentInf();  
    string ReturnName();  
};  
#endif  

 

注:#ifndef相当于if-not-define,#endif是#ifndef结束语句的宏标志,#define Cstudent_H ……#endif,从Cstudent_H到#endif之间都是Cstudent_H的内容。他们的功能就在于可以在预编译过程中确定程序编译的大体逻辑思路,避免因为互相引用而导致的无限死循环调用。

全部代码演示:

① Cstudent.h文件

#pragma once  
  
#include <string>  
using namespace std;  
  
#ifndef Cstudent_H  
#define Cstudent_H  
class Cteacher; // 声明一下Cteacher类  
class Cstudent  
{  
private:  
    string Sname;  
    string Sposition;  
    int Sage;  
public:  
    Cteacher *teacher; // 一定要声明为共有类型的,如果在构造函数中初始化,会嵌套调用两者的构造函数  
public:  
    Cstudent(string name, string position, int age);  
    ~Cstudent();  
    void ShowTeacherInf();  
    string ReturnName();  
};  
#endif  

 

② Cteacher.h文件

#pragma once  
  
#include <string>  
using namespace std;  
  
#ifndef Cteacher_H  
#define Cteacher_H  
class Cstudent;  
class Cteacher  
{  
private:  
    string Tposition;  
    string Tname;  
    int Tage;  
public:  
    Cstudent *stud; // 未声明类体的类可以定义指针,但绝对不可以定义变量,因为没有实体,系统不知道内存怎么分配  
public:  
    Cteacher(string Tname, string Tposition, int Tage);  
    ~Cteacher();  
    void ShowStudentInf();  
    string ReturnName();  
};  
#endif  

 

③ Cstudent.cpp

#include <iostream>  
#include <string>  
#include "Cstudent.h"  
#include "Cteacher.h"  
using namespace std;  
  
Cstudent::Cstudent(string Sname, string Sposition, int Sage)  
{  
    this->Sname = Sname;  
    this->Sposition = Sposition;  
    this->Sage = Sage;  
}  
  
Cstudent::~Cstudent()  
{  
    cout << "调用Cstudent析构函数" << endl;  
}  
  
void Cstudent::ShowTeacherInf()  
{  
    cout << this->Sname << "的老师为" << teacher->ReturnName() << endl;  
}  
  
std::string Cstudent::ReturnName()  
{  
    return this->Sname;  
}  

 

④ Cteacher.cpp文件

#include <string>  
#include <iostream>  
#include "Cteacher.h"  
#include "Cstudent.h"  
using namespace std;  
  
Cteacher::Cteacher(string Tname, string Tposition, int Tage)  
{  
    this->Tname = Tname;  
    this->Tposition = Tposition;  
    this->Tage = Tage;  
}  
  
Cteacher::~Cteacher()  
{  
    cout << "调用Cteacher析构函数" << endl;  
}  
  
void Cteacher::ShowStudentInf()  
{  
    cout << this->Tname << "的学生姓名为" << stud->ReturnName() << endl;  
}  
  
std::string Cteacher::ReturnName()  
{  
    return this->Tname;  
}  

 

⑤ main函数文件

#include <iostream>  
#include <string>  
#include "Cstudent.h"  
#include "Cteacher.h"  
using namespace std;  
  
int main()  
{  
    Cstudent stud{ "超级霸霸强","学生",18 };  
    Cteacher teacher{ "好老师","老师",66 };  
    stud.teacher = &teacher;  
    teacher.stud = &stud;  
    stud.ShowTeacherInf();  
    teacher.ShowStudentInf();  
}  

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

肥肥胖胖是太阳

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

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

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

打赏作者

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

抵扣说明:

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

余额充值