1 / 62

C++

C++. 课程适用性. 迫于时间所限,本课程只能面向 C 语言程序设计基础较好的 同学。 希望 经过短期训练, 让大家能 读 懂 WrightEagleBASE 中涉及语言特性的部分。 合格的 C++ 入门和参考书籍 有 C ++ Primer 、 The C++ Programming Language 和 Thinking in C ++ 。. C 语言复习. 整型. 浮点型. 浮点数也是离散的。 浮点数的内部表示也是二进制,比如 float ,一共 32 个二进制位, 所以不可能 表示出超过 2^32 个数字。 IEEE 754 浮点数的比较

Download Presentation

C++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C++

  2. 课程适用性 • 迫于时间所限,本课程只能面向C语言程序设计基础较好的同学。 • 希望经过短期训练,让大家能读懂WrightEagleBASE中涉及语言特性的部分。 • 合格的C++入门和参考书籍有C++ Primer、The C++ Programming Language和Thinking in C++。

  3. C语言复习

  4. 整型

  5. 浮点型 • 浮点数也是离散的。 • 浮点数的内部表示也是二进制,比如float,一共32个二进制位,所以不可能表示出超过2^32个数字。 • IEEE 754 • 浮点数的比较 • if (a == b) X • if (fabs(a-b) < FLT_EPSILON)O • if (fabs(a-b) < DBL_EPSILON) O

  6. 其它类型 • _Bool • float _Complex / double _Complex(复数) ——c99 • 衍生类型 • array、structure、union、function、pointer • 类型限定符 • const、volatile、restrict • void类型 • 取值集合为空集的类型

  7. Union类型 union a{ double x; inti; }; ——X与i公用一个内存位置,同一时间只能保存一个成员。

  8. Volatile限定符 • volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。 • 如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象.

  9. Volatile代码示例 short flag;void test(){ do1(); while(flag==0); do2();}

  10. Volatile代码示例 volatile short flag;void test(){ do1(); while(flag==0); do2();}

  11. Const限定符 constint a=10; int * b=&a; 虽然,编译器会报警告“ 警告:初始化丢弃了指针目标类型的限定”,这个意思是,b失去了对目标对象的const的限定。但是通过,并且,可以通过指针b更改它们共同指向的空间。

  12. Const限定符 constint a=10; int b=(int)&a; int * c=(int *)b; 这种写法和上面的效果一样,却连警告都不报,

  13. Restrict限定符 restrict只可以用在指针身上。如果一个指针被restrict修饰,那么就在它(这个指针)和它所指向的对象之间建立了一种特殊的联系──只能用这个指针或者这个指针的表达式来访问这个对象的值.

  14. 指针 • float * const float指针常量类型 ——常量指针,指针的值不能变 • const float * 常量float类型的指针类型 ——指向常量的指针,指向的内存不能变 • DecisionDataDerived** 指针的指针 • E1[E2]  (*((E1)+(E2))) • A[3]  *(A+3) • 3[A]  *(3+A) = *(A+3)

  15. const和#define定义常量的异同 • #define属于预编译的范围,“符号替换”(无类型);const定义的是“不能修改的”变量(有类型)。 • #define只能定义有“字面值”的常量;const可以定义数组、结构体和union常量(实际上是变量)。 • enum可以定义整数常量,一般用于互相关联的一组整数。 • enumPlayMode{}

  16. #define • #define  SQUARE(x)   x*x 错误 • #define   SQUARE(x)   (x)*(x) 正确 • 对于第一种:SQUARE(6-1),在编译时会被替换成了6-1*6-1

  17. 预编译指令 • #include 后面不是“字符串”,是用引号或者<>括起来的文件名。 • 条件编译 • #define 符号 • #undef符号 • #if / #elif字面值常量表达式 • #ifdef / #ifndef / #else 符号 • 不符合#if条件的代码段编译器不编译

  18. 预编译指令 • #define中“#”的用法 • #x 将x变成字符串 • x##y 将x与y连接起来 • #define TeammateFormationTactic(TacticName) (*(FormationTactic##TacticName *)mFormation.GetTeammateTactic(FTT_##TacticName)) • TeammateFormationTactic(KickOffPosition)  *(FormationTacticKickOffPosition*)mFormation.GetTeammateTactic(FTT_KickOffPosition))

  19. 其它 • sizeof运算符 • size_tfsize(int n) { char t[n+3]; return sizeof(t);}fsize(10) -> 13 • inline函数 • static变量

  20. 堆、栈图示

  21. C++标签

  22. 即时声明 • C语言要求所有变量的声明必须在实意语句之前,也就是在所有{}的外面,或者是每对{}的最前面。 • C++没有了这样的限制,变量只要遵循先声明后使用的原则就可以了,不再要求必须放在什么地方。我们可以在for语句头部塞上一个inti(0),for (inti(0); i < 10; ++i)。 • “inti(0)”里的(0)是指将i初始化为0,作用相当于inti=0。

  23. 引用 • 引用(reference)是C++新定义的一种复合类型,其本意可以理解为变量的“别名(alternate name)”。 • 声明/定义一个引用:int a;int & r = a; • 声明引用时,必须同时对其进行初始化。 • r被定义为a的引用后,r和a可以被认为是同一个变量。 • 引用的主要用在函数形参中(作用与指针相仿): • 避免传递规模巨大的实参; • 将形参的值返回。

  24. 引用 • void BehaviorAttackPlanner::Plan(std::list<ActiveBehavior> & behavior_list) • PlayerState & player = const_cast<PlayerState &>(*mpWorldState->GetPlayerList()[i]);player.GetPos();

  25. 左值与右值

  26. i++与++i编译器实现 • i++的实现是:    int   temp;    temp   =   i;   i   =   i+1;   return   temp;    • ++i的实现是:   i  =   i+1;     return   i;               

  27. 类型转换 • C++继承了原有的C语言的隐式类型转换; • 所有的类型都可以隐式转换为该类型的引用:int => int &,int * => int * &,所有的类型都可以隐式转换为该类型的常量; • 强制类型转换在C++中有了另一类写法: • (type) a  xxx_cast<type> a; • static_cast<type>实现与C中类型转换相同的功能; • const_cast<type>去掉表达式的常量性; • 另外还有reinterpret_cast和dynamic_cast

  28. Const_cast<type>解析 • #include <stdio.h>  • int main(intargc, char* argv[]) • { • constintic = 100; • constint *pc=&ic; • const_cast<int &>(ic)++; • printf("%d,%d\n", ic, *pc); •      return 0; • } 输出: ——100,101 慎用!!!

  29. 输入输出 • std::cout<< a << b << c << d <<std::endl; • Logger::instance().GetTextLogger(“test”) << a << b << c << d <<std::endl; • 输出到Logfiles/WrightEagle-X-test.log中。

  30. 形参默认值 • 形参允许有默认值,即函数可以声明为如下形式:boolKickBall( Agent & agent, double angle, double speed_out,KickModemode = KM_Hard,int*cycle_left = 0,boolis_shoot = false);

  31. 形参默认值 • 调用的时候可以不写有默认值的参数 • KickBall(agent, 0.0, 3.0); • KickBall(agent, 0.0, 3.0, KM_Quick); • KickBall(agent, 0.0, 3.0, KM_Quick, &cycle); • KickBall(agent, 0.0, 3.0, KM_Quick, &cycle, true); • 都是合法的 • 没写的参数,实参值就是默认值。

  32. 函数重载 • 允许不同的函数有相同的函数名。 • “不同的函数”是指形参的类型、数目或返回值的类型不同的函数。 • boolGoToPoint(Agent & agent, Vector pos, double buffer = 0.5, double power = 100.0, boolcan_inverse = true, boolturn_first = false); • void GoToPoint(Agent & agent, AtomicAction & act, Vector pos, double buffer = 0.5, double power = 100.0, boolcan_inverse = true, boolturn_first = false);

  33. new和delete运算符 • C语言用malloc和free。 • C++用new和delete。 • client = new Player; • delete client; • mWeight = new real**[mLayers]; • delete[] mWeight;

  34. 面向对象的C++

  35. • 类是C++的新特性,为适应面向对象的程序设计而提出; • 在C中,已经有了结构体的概念; • 类与结构体的最大不同之处在于——不仅可以包含成员变量(常量),还可以包含成员函数。 • 当然,类还包括一些其他的特性: • 成员变量、成员函数的访问权限; • 构造函数; • 析构函数; • 拷贝构造函数; • 隐式类型转换; • ……

  36. 成员属性 • private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.  • protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问  • public: 可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问

  37. 静态成员 • static关键字也可以修饰类的成员 • class Dasher{public:static Dasher & instance();static Array<double, 8> DASH_DIR;static Array<int, 8> ANTI_DIR_IDX;static Array<double, 8> DIR_RATE;static intGetDashDirIdx(constAngleDeg & dir);}

  38. 静态成员 • 被修饰的成员叫做类的静态成员,是这个类的属性,不是某个对象的属性。 • 访问用:: • Dasher::instance() • Dasher::GetDashDirIdx()

  39. 一个著名的类 class BaseState { public: BaseState(); BaseState(constBaseState & o) {} void UpdatePos(const Vector & pos , int delay = 0, double conf = 1); const Vector & GetPos() const { return mPos.mValue; } intGetPosDelay() const { return mPos.mCycleDelay; } const double & GetPosConf() const { return mPos.mConf; } void UpdatePosEps(double eps) { mPosEps = eps;} const double & GetPosEps() const { return mPosEps;} private: doubleStateValue<Vector> mPos; mPosEps; };

  40. 成员函数的定义 • 成员函数可以直接在类定义里定义,也可以单独在外面定义。 • void BaseState::UpdatePos(const Vector & pos, int delay, double conf){mPos.mValue = pos;mPos.mCycleDelay = delay;mPos.mConf = conf;}

  41. this指针 • 每个类都有一个特殊的“成员”——this,表示对象自身; • this只能在该类的内部使用,与不指明this没有区别: • this->mPos mPos • this->mPosConf  mPosConf • void UpdatePosEps(double mPosEps) { this->mPosEps= mPosEps;}

  42. 成员函数的const属性 • constVector & GetPos() const • GetPos不能更改任何成员变量的值,在函数内部 • this指针变成指向常量的指针; • 任何成员变量被附加const属性。 • 这种声明主要用于指明该函数不会更改成员变量的值。

  43. 构造函数 • 没有返回值类型,与类同名的函数被认为是构造函数。BaseState() • 它的作用就是——构造一个对象。 • BaseState() : mPosEps(10000);{mPos.mValue= Vector(10000 , 10000);}

  44. 构造函数 • 如果你只是声明一个空类,不做任何事情的话,编译器会自动为你生成一个默认构造函数、一个拷贝默认构造函数、一个默认拷贝赋值操作符和一个默认析构函数。 • 如果定义了构造函数(不管有参无参),则编译器不会生成默认构造函数 • Note:自己定义无参的默认构造函数

  45. 构造函数 • 拷贝构造函数与 = 运算符重载 • BaseState(const BaseState & o) { mPos = o.mPos;}//一个拷贝构造函数 • = 运算符重载 • BaseState operator = (const BaseState & o) • {}

  46. 构造函数 • 如果将某个构造函数声明为private,则这个构造函数将无法使用。一般来说,这样做的目的是阻止编译器生成缺省的构造函数,或用于singleton模式(一种设计模式,只允许某个类有单个实例)。 • class Agent{ Agent(Agent &); ……};

  47. 补充:singleton模式 • class Singleton{ • public: • static Singleton * Instance(){ • if( 0== _instance){ • _instance = new Singleton; • } • return _instance; • } • private: • Singleton(void){ • } • static Singleton* _instance; • };

  48. 构造函数 • class Line {public: Line(constRay &r); ……}; • 只带有一个参数的构造函数表明了一种可能的隐式类型转换。 • 例子: • Ray a; • Line b; • b = a;//合法,执行Line(a)转换

  49. 构造函数 • 在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数 • 例: • Box(int =10,int =10,int =10);        1Box();                               2Box(int,int);                        3 • 若有以下定义语句:Box box1;                 //是调用上面的第一个默认参数的构造函数,还是第二个默认构造函数Box box2(15,30);          //是调用上面的第一个默认参数的构造函数,还是第三个构造函数

  50. 析构函数 • 没有返回值,名字是~<class name>,没有参数的函数是析构函数。构造函数可以有多个,析构函数只能有一个。 • 它的作用是销毁一个对象。 • 如果没有声明析构函数,编译器将合成默认析构函数 • 对于内置类型,释放其空间; • 对于类类型,调用其析构函数。 • 实际上,上面两步是编译器附加在任何析构函数最后的两步。 • 显式调用的时候,析构函数相当于的一个普通的成员函数,只是单纯的执行函数体中的语句,不会销毁对象。

More Related