目录
不为人知的#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();
}