C++学习系列笔记(六)

举报
小小谢先生 发表于 2022/04/16 01:39:19 2022/04/16
【摘要】 1、类型转换运算符 C++提供了一种新的类型转换运算符,专门用于基于继承的情形,这种情形在C语言编程中并不存在。4个C++转换类型如下; static_castdynamic_castreinterpret_castconst_cast 这4个类型转换运算符的使用语法相同:destnation_type resulr = cast_t...

1、类型转换运算符
C++提供了一种新的类型转换运算符,专门用于基于继承的情形,这种情形在C语言编程中并不存在。4个C++转换类型如下;

  • static_cast
  • dynamic_cast
  • reinterpret_cast
  • const_cast
    这4个类型转换运算符的使用语法相同:
    destnation_type resulr = cast_type<destination_type> (object_to_be_casted);
    使用static_cast
    使用static_cast可将指针向上转换为基类类型,也可向下转换为派生类型,如下面的示例代码所示:

  
  1. Base* pBase=new Derived (); //constract a Derived object
  2. Derived* pDerived=static_cast<Derived*>(pBase); //ok!

PS : 将 Derived转换为 Base被称为向上转换,无需使用任何显式类型转换运算符就能进行这种转换:


  
  1. Derived objDerived;
  2. Base* pBase = &objDerived; //ok

将 Base转换为 Derived被称为向下转换,如果不使用显式类型转换运算符,就无法进行这种转换.
除用于向上转换和向下转换外,static_cast还可在很多情况下将隐式类型转换为显式类型,以引起程序员或代码阅读人员的注意:


  
  1. double dPi = 3.14159265;
  2. int Num = static_cast<int>(dPi);

使用dynamic_cast和运行阶段类型识别
顾名思义,与静态类型转换相反,动态类型转换在运行阶段(即应用程序运行时)执行类型转换。可检查 dynamic_cast操作的结果,以判断类型转换是否成功。使用 dynamic_cast运算符的典型语法如下:


  
  1. destination_type* pDest = dynamic_cast <class_type*> (pSource);
  2. if (pDest) //check for sucess of the casting operation before using pointer
  3. pDest->CallFunc();

实例代码如下:


  
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. class Fish
  5. {
  6. public:
  7. virtual void Swim()
  8. {
  9. cout << "Fish swims in water" << endl;
  10. }
  11. virtual ~Fish() {}
  12. };
  13. class Tuna:public Fish
  14. {
  15. public:
  16. void Swim()
  17. {
  18. cout << "Tuna swims real fast in the sea" << endl;
  19. }
  20. void BecomeDinner()
  21. {
  22. cout << "Tuna become dinner in sushi" << endl;
  23. }
  24. };
  25. class Carp :public Fish
  26. {
  27. public:
  28. void Swim()
  29. {
  30. cout << "Carp swims real slow in the lake" << endl;
  31. }
  32. void Talk()
  33. {
  34. cout << "Carp talked crap" << endl;
  35. }
  36. };
  37. void DetectFishType(Fish* InputFish)
  38. {
  39. Tuna* pIsTuna = dynamic_cast <Tuna*>(InputFish);
  40. if (pIsTuna)
  41. {
  42. cout << "Detect Tuna. making Tuna Dinner:" << endl;
  43. pIsTuna->BecomeDinner();
  44. }
  45. Carp* pIsCarp = dynamic_cast <Carp*>(InputFish);
  46. if (pIsCarp)
  47. {
  48. cout << "Detect Carp. making Carp Talk:" << endl;
  49. pIsCarp->Talk();
  50. }
  51. cout << "Verifing type using virtual Fish::Swim:" << endl;
  52. InputFish->Swim();
  53. }
  54. int main()
  55. {
  56. Carp myLunch;
  57. Tuna myDinner;
  58. DetectFishType(&myDinner);
  59. cout << endl;
  60. DetectFishType(&myLunch);
  61. return 0;
  62. }

程序输出结果:


  
  1. Detect Tuna. making Tuna Dinner:
  2. Tuna become dinner in sushi
  3. Verifing type using virtual Fish::Swim:
  4. Tuna swims real fast in the sea
  5. Detect Carp. making Carp Talk:
  6. Carp talked crap
  7. Verifing type using virtual Fish::Swim:
  8. Carp swims real slow in the lake

使用reinterpret_cast
reinterpret_cast是C++中与C风格类型转换最接近的类型转换运算符。它让程序员能够将一种对象类型转换为另一种,不管它们是否相关;也就是说,它使用如下所示的语法强制重新解释类型:


  
  1. Base* pBase=new Derived ();
  2. CUnrelated * pUnrelated = reinterpret_cast<CUnrelated*>(pBase);

这种类型转换实际上是强制编译器接受static_cast通常不允许的类型转换,通常用于低级程序(如驱动程序).
注意:使用reinterpret_cast时,程序员将收到类型转换不安全(不可移植)的警告。应尽量避免在应用程序中使用 reinterpret_cast。
使用const_cast
const_cast让程序员能够关闭对象的访问修饰符 const。您可能会问:为何要进行这种转换?在理想情况下,程序员将经常在正确的地方使用关键字const。不幸的是,现实世界并非如此。如下面代码所示


  
  1. class SomeClass
  2. {
  3. public:
  4. //……
  5. void DisplayMembers; //a display function ought to be const
  6. };

然而,DisplayMembers()本应为 const 的,但却没有这样定义。如果 SomeClass 归您所有,且源代码受您控制,则可对DisplayMembers()进行修改。然而,在很多情况下,它可能属于第三方库,无法对其进行修改。在这种情况下,const_cast将是您的救星。


  
  1. void DisplayMembers(const SomeClass& mData)
  2. {
  3. mData.DisplayMembers(); //编译错误
  4. //reason for failure:call to a non-const member using a const refernence
  5. }

所以应该这样修改:


  
  1. void DisplayMembers(const SomeClass& mData)
  2. {
  3. SomeClass& refData = const_cast<SomeClass&>(mData)
  4. refData.DisplayMembers(): //Allowed!
  5. }

除非万不得已,否则不要使用const_cast来调用非const函数。一般而言,使用const_cast来修改const对象可能导致不可预料的行为。
2、宏和模板简介
2.1 预处理器与编译器
定义常量
#define identifier value
使用宏避免多次包含
在预处理器看来,两个头文件彼此包含对方会导致递归问题。为避免这种问题,可结合使用宏以及预处理器编译指令#ifndef和#endif。
包含<header2.h>的head1.h类似于下面这样:


  
  1. #ifndef HEADER1_H_
  2. #define HEADER1_H_
  3. #include<header2.h>
  4. class Class1
  5. {
  6. //code
  7. };
  8. #endif //end of header1.h

header2.h与1差不多,替换一下就可以了。
预处理器首次处理header1.h并遇到#ifndef后,发现宏HEADER1_H_还未定义,因此继续处理。#ifndef后面的第一行定义了宏HEADER1_H_,确保预处理器再次处理该文件时,将在遇到包含#ifndef的第一行时结束,因为其中的条件为false。
2.2、使用define定义宏函数
典型代码:#define SQUARE(x) ((x)*(x))
宏函数经常进行简单的计算,有助于改善代码的性能。
使用assert()宏验证表达式
assert宏让您能够插入检查语句,对表达式或变量的值进行验证。要使用assert宏,需要包含<assert.h>,其语法如下:


  
  1. #include<assert.h>
  2. int main()
  3. {
  4. char* SayHello = new char [25];
  5. assert(SayHello!=NULL);
  6. //other code;
  7. delete[] SayHello;
  8. return 0;
  9. }

上述代码在指针无效时可以指出来。
2.3、模板简介
模板声明以关键字template打头,接下来是类型参数列表。这种声明的格式template <parameter list>
示例代码如下:


  
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. template <typename Type>
  5. const Type& GetMax(const Type& value1, const Type& value2)
  6. {
  7. if (value1 > value2)
  8. return value1;
  9. else
  10. return value2;
  11. }
  12. template <typename Type>
  13. void Displaycomparison(const Type& value1, const Type& value2)
  14. {
  15. cout << "GetMax(" << value1 << "," << value2 << ")=";
  16. cout << GetMax(value1, value2) << endl;
  17. }
  18. int main()
  19. {
  20. int a1 = -101, int a2 = 2011;
  21. Displaycomparison(a1, a2);
  22. double d1 = 3.14, double d2 = 3.1415926;
  23. Displaycomparison(d1, d2);
  24. string Name1("Jack"), Name2("john");
  25. Displaycomparison(Name1, Name2);
  26. return 0;
  27. }

模板函数不仅可以重用(就像宏函数一样),而且更容易编写和维护,还是类型安全的。 请注意,调用Displaycomparison时,也可显式地指定类型,如下所示:
Displaycomparison<int>(Int1,Int2);
然而,调用模板函数时没有必要这样做。您无需指定模板参数的类型,因为编译器能够自动推断出类型;但使用模板类时,需要这样做。
2.4、模板类
模板类是模板化的 C++类,是蓝图的蓝图。使用模板类时,可指定要为哪种类型具体化类。这让您能够创建不同的Human对象,即有的年龄存储在 long long成员中,有的存储在 int成员中,还有的存储在short成员中。
对于模板,术语实例化的含义稍有不同。用于类时,实例化通常指的是根据类创建对象。但用于模板时,实例化指的是根据模板声明以及一个或多个参数创建特定的类型。
对于下面的模板声明:


  
  1. template <typename T>
  2. class TemplateClass
  3. {
  4. T m_member;
  5. };

使用模板是将这样编写代码

TemplateClass <int> IntTemplate;

 

这种实例化创建的特定类型称为具体化。
声明包含多个参数的模板
如下面代码所示:


  
  1. template <typename T1, typename T2>
  2. class HoldsPair
  3. {
  4. private:
  5. T1 Value1;
  6. T2 Value2;
  7. public:
  8. HoldsPair(const T1& value1,const T2& value2)
  9. {
  10. Value1=value1;
  11. Value2=value2;
  12. }
  13. //other function declarations
  14. };

实例化如下:


  
  1. HoldsPair<int,double> pairIntDouble(6,1.99);
  2. HoldsPair<int,int> pairIntDouble(6,500);

包含默认参数的模板


  
  1. template <typename T1=int,typename T2=int>
  2. class HoldsPair
  3. {
  4. //……method declare
  5. };

实例化可简写为:

HoldsPair <> PairIntDouble(6,500);

 

实例代码如下:


  
  1. #include<iostream>
  2. using namespace std;
  3. template <typename T1=int,typename T2=double>
  4. class HoldsPair
  5. {
  6. private:
  7. T1 Value1;
  8. T2 Value2;
  9. public:
  10. HoldsPair(const T1& value1, const T2& value2)
  11. {
  12. Value1 = value1;
  13. Value2 = value2;
  14. };
  15. const T1 & GetFirstvalue() const
  16. {
  17. return Value1;
  18. };
  19. const T2& GetSecondvalue() const
  20. {
  21. return Value2;
  22. };
  23. };
  24. int main()
  25. {
  26. HoldsPair<> mIntFloatPair(300, 10.09);
  27. HoldsPair<short,const char*> mshortstringPair(25, "learn template,love c++");
  28. cout << "the first object conntains-" << endl;
  29. cout << "Value 1:" << mIntFloatPair.GetFirstvalue() << endl;
  30. cout << "Value 2:" << mIntFloatPair.GetSecondvalue() << endl;
  31. cout << "the second object contains-:" << endl;
  32. cout << "Value 1:" << mshortstringPair.GetFirstvalue() << endl;
  33. cout << "Value 2:" << mshortstringPair.GetSecondvalue() << endl;
  34. return 0;
  35. }

输出为:


  
  1. the first object conntains-
  2. Value 1:300
  3. Value 2:10.09
  4. the second object contains-:
  5. Value 1:25
  6. Value 2:learn template,love c++

模板类和静态成员
实力代码如下:


  
  1. #include<iostream>
  2. using namespace std;
  3. template <typename T>
  4. class TestStatic
  5. {
  6. public:
  7. static int StaticValue;
  8. };
  9. template<typename T> int TestStatic<T>::StaticValue;
  10. int main()
  11. {
  12. TestStatic<int> Int_Year;
  13. cout << "setting staticvalue for Int_Year to 2011" << endl;
  14. Int_Year.StaticValue = 2011;
  15. TestStatic<int> Int_2;
  16. TestStatic<double> Double_1;
  17. TestStatic<double> Double_2;
  18. cout << "setting staticvalue for Double_2 to 1011" << endl;
  19. Double_2.StaticValue = 1011;
  20. cout << "Int_2.StaticValue= " << Int_2.StaticValue << endl;
  21. cout << "Double_1.StaticValue= " << Double_1.StaticValue << endl;
  22. return 0;
  23. }

输出为:


  
  1. setting staticvalue for Int_Year to 2011
  2. setting staticvalue for Double_2 to 1011
  3. Int_2.StaticValue= 2011
  4. Double_1.StaticValue= 1011

上述有一条程序初始化模板类的静态成员:template<typename T> int TestStatic<T>::StaticValue
对于模板类的静态成员,通用的初始化语法如下:

template<typename parameters> staticType ClassName<Template Arugments>::StaticVarName;

 

使用static_assert执行编译阶段检查
tatic_assert是C++11新增的一项功能,让您能够在不满足指定条件时禁止编译。语法如下:
static_assert(expression being validated, "error message when check fails"
要禁止针对类型int实例化模板类,可使用static_assert(),并将sizeof(T)与sizeof(int)进行比较,如果它们相等,就显示一条错误消息:

static_assert(sizeof(T)!=sizeof(int), "No int please!");

 

示例代码如下


  
  1. #include<iostream>
  2. using namespace std;
  3. template <typename T>
  4. class everythingbutInt
  5. {
  6. public:
  7. everythingbutInt()
  8. {
  9. static_assert(sizeof(T) != sizeof(int), "Not int please!");
  10. }
  11. };
  12. int main()
  13. {
  14. everythingbutInt<int> test;
  15. return 0;
  16. }

文章来源: blog.csdn.net,作者:小小谢先生,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/xiewenrui1996/article/details/100584766

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。