9512.net
甜梦文库
当前位置:首页 >> 计算机软件及应用 >>

C++基本概念


解释型语言和编译型语言有何不同? 答:如 windows script 等语言是解释型的,不需要编译。解释型语言使用解释器,解释器 直接读取脚本文件(代码)并执行指定的操作。在运行阶段,解释器在微处理器和代码之间 充当翻译,因此性能通常会受影响。 解释器和编译器有何不同? 答:解释器是一种对代码(或字节码)进行解释并执行相应操作的工具;编译器将代码作为 输入,并生成目标文件。 链接器的作用是什么? 答:编译器将代码文件作为输入,并生成一个使用机器语言的目标文件。通常,这些代码依 赖于库和其他代码文件中的函数。链接器负责建立这些链接,并生成一个可执行文件。 C++11 标准如何更好的支持多核 CPU? 答:C++支持可移植的线程模型,能够使用标准 C++线程函数创建多线程应用程序。通过在 多个 CPU 核心中同时执行应用程序的不同线程,最大限度地发挥多核处理器的潜力。 变量类型表 P20 为何应给变量初始化? 答:有时候,需要根据变量的值(通常核实它不为 0)做条件处理,如果不对变量进行初始 化,这样的逻辑将不可靠,因为未赋值或初始化的变量包含的内容是随机的。 为何不应使用#define 来声明常量? 答:#define 是一个预处理器编译指令,让编译器对定义的值进行文本替换。然而,它不是 类型安全的,是一种原始的常量定义方式,应使用关键 const 声明常量。 常量可以是:1. 2. 3. 4. 5. 字面常量 使用关键字 const 声明的常量 使用关键字 constexpr 声明的常量表达式(C++11) 使用 enum 声明的枚举常量 使用#define 定义的常量(不推荐)

constexpr 用法:constexpr double GetPi() {return 22.0 /7;} 还可以将 GetPi()与另一个常量一起使用,如: constexpr double TwicePi() {return 2 * GetPi();} const 和 constexpr 之间的差别很小,但对于第二条语句,如果使用 const,将在运行阶段 执行计算, 但使用 constexpr, 将在编译阶段计算该表达式的值, 提高了应用程序运行速度。 C++关键字表 P28 相对于 C 风格的字符串,为什么 C++的 std:string 更安全? 答:C 风格字符串作为输入的函数非常危险,因为它们会寻找终止空字符,如果程序员没有 在字符数组末尾添加空字符,这些函数将跨越字符数组的边界。而 std:string 是动态的,

在需要储存更多数据时其容量将增大。 运算符优先级表 P58

对于使用 new[…]分配的内存块, 需要使用 delete[]来释放; 对于使用 new 为单个元素分配 的内存,需要使用 delete 来释放。 (它们是运算符) new 的变种——new(nothrow),它在内存分配失败时不引发异常,而返回 NULL

将关键字 const 用于引用 int Original = 30; cons tint& ConstRef = Original; ConstRef = 40; //Not allowed: ConstRef can?t change value in Original int& Ref2 = ConstRef; //Not allowed: Ref2 is not const cons tint& ConstRef2 = ConstRef; //OK 将关键字 const 用于指针 int Number = 30; cons tint* pNumber = &Number; int* pAnother = pNumber; //can?t assign pointer to const to a non-const 即不能修改指针的 const 程度 引用时真正的别名,将参数传递给函数时,引用可很好地替代指针,因为引用总是有效,而 指针可能无效,而且,如果函数接收非常大的对象,按值传递开销较大。

可在不提供参数的情况下调用的构造函数被称为默认构造函数, 并不一定是不接受任何参数 的构造函数,为参数提供默认值的也是默认构造函数。默认构造函数是可选的,如果没有提 供默认构造函数, 编译器将自动创建一个。 但没有默认构造函数, 而提供了重载构造函数时, C++编译器不会生成默认构造函数。 析构函数不能重载,每个类只能有一个析构函数,如果忘了实现析构函数,编译器将创建一 个伪(dummy)析构函数并调用它,伪析构函数为空,即不释放动态分配的内存。

如果类中包含一个指针成员,它指向动态分配的内存,复制这个类的对象时(比如向函数参 数传递对象时) ,将复制其指针成员,但不复制指针指向的缓冲区,其结果是,两个对象指 向同一块动态分配的内存。这被称为浅复制,会威胁程序的稳定性。 使用复制构造函数确保深复制 例: MyString(const MyString& CopySource)

//必须按引用传递

{ if (CopySource.Buffer != NULL) { Buffer = new char [strlen(CopySource.Buffer) + 1]; strcpy(Buffer, CopySource.Buffer); } else Buffer = NULL; } 同样,如果不指定恰当的重载赋值运算符,编译器提供的默认赋值运算符将导致浅复制 例: MyString& operator = (const MyString& CopySource) { if ((this != &CopySource) && (CopySource.Buffer != NULL)) { if (Buffer != NULL) delete Buffer; Buffer = new char [strlen(CopySource.Buffer) + 1]; strcpy(Buffer, CopySource.Buffer); } return this; } 扩展:移动构造函数 P142 构造函数和析构函数的其他用途 1 不允许复制的类 要禁止类对象被复制,可声明一个私有的复制构造函数,为禁止赋值,可声明一个私有的复 制运算符。 无需给私有复制构造函数和私有赋值运算符提供实现, 只需将它们声明为私有的 就行了。 2 只能有一个实例的单例类 提示:static 的作用: 将关键字 static 用于函数中声明局部变量时,该变量的值将在两次调用之间保持不变; 将 static 用于类的数据成员时,该数据成员将在所有实例之间共享; 将 static 用于成员函数(方法)时,该方法将在所有成员之间共享。 把默认构造函数声明为私有, 禁止在外部创建实例, 而只能通过公共静态成员函数来创建静 态实例,创建后赋给该对象类型的一个引用,并用上面的方法禁止复制及赋值。 3 禁止在栈中实例化类 像一些较大的数据库类,可能禁止在栈上实例化,而只允许在堆上创建其实例。为此,关键 在于将析构函数声明为私有。但这样由于 main 函数不能调用析构函数,因此也不能使用 delete, 将导致内存泄露, 因此需要在类中提供一个销毁实例的静态公有函数 (作为类成员,

它能够调用析构函数) 。

基类也被称为超类;从基类派生而来的类称为派生类,也叫子类。 将属性声明为 protected 时,相当于允许派生类和友元类访问它,但禁止在继承层次结构外 部访问它。要让派生类能够访问基类的某个属性,可使用访问限定符 protected。 基类的初始化——向基类传递参数: 使用初始化列表, 并通过派生类的构造函数调用合适的 基类构造函数。 例: class Base { public: Base(int SomeNumber) { //do something with SomeNumber } }; class Derived: public Base { public: Derived(): Base(25) //instantiate class Base with argument 25 { //derived class constructor code } }; 在派生类中覆盖基类的方法: 如果派生类实现了从基类继承的函数, 且返回值和特征标相同, 就相当于覆盖了基类的这个方法。 例: class Base { public: void DoSomething() { //implementation code… Does something } }; class Derived: public Base { public: void DoSomething() {

//implementation code…Does something else } }; 如果 Derived 类的实例调用方法 DoSomething(),调用的将不是 Base 类中的这个方法。 要调用基类中被覆盖的方法: 1 使用作用域解析运算符(::) :DerivedObject.Base::DoSomething(); 覆盖的一种极端情形:Derived::DoSomething()可能会隐藏 Base::DoSomething()的所有重 载版本。如果 Base 类中有 DoSomething()的重载版本如 Base::DoSomething(bool),那么 要通过 Derived 实例调用 Base::DoSomething(bool),可采用下面方案: 2 使用关键字 using 解除对 Base::DoSomething()的隐藏 例: class Derived: public Base { public: using Base::DoSomething; //unhide DoSomething methods in base class Base, no() void DoSomething() { //implementation code…Does something else } }; 3 例: class Derived: public Base { public: void DoSomething(bool dofou) { Base::DoSomething(dofou); } void DoSomething() { //implementation code…Does something else } };

保护继承与私有继承的类似处: 1. 它让派生类能够访问基类的所有公有和保护成员 2. 在继承层次结构外面,也不能通过派生类实例访问基类的公有成员 但随着继承层次结构的加深,保护继承将与私有继承有些不同。

对于大多数使用私有继承的情形,更好的选择是,将基类对象作为派生类的一个成员属性。 将基类对象作为派生类的私有成员被称为组合(composition)或聚合(aggregation)

可在基类中将方法声明为虚函数可实现多态: class Base { virtual ReturnType FunctionName(Parameter List); }; class Derived: public Base { ReturnType FunctionName(Parameter List); }; 通过基类的指针或引用调用方法 FunctionName()可确保编译器调用覆盖版本。 这就是多态:将派生类对象视为基类对象,并执行派生类的方法实现。 对于使用 new 在自由存储区中实例化的派生类对象,如果将其赋给基类指针,并通过该指 针调用 delete,将不会调用派生类的析构函数。这可能导致资源未释放、内存泄露等问题。 要避免这种问题,可将基类的析构函数声明为虚函数。

纯虚函数和抽象基类:不能实例化的基类(只要包含至少一个纯虚函数)被称为抽象基类 class AbstractBase { public: virtual void DoSomething() = 0; //pure virtual method }; 该声明告诉编译器,AbstractBase 的派生类必须实现方法 DoSomething(),这让基类可指 定派生类中方法的名称和特征(Signature) ,即指定派生类的接口。 如果派生类可能被用作基类,派生它时最好使用关键字 virtual,即使用虚继承。在继承层次 结构中,继承多个从同一个类派生而来的基类时,如果这些基类没有采用虚继承,将导致二 义性(即菱形问题) 。 构造函数只能创建固定类型的对象,不具备多态性,因此 C++不允许使用虚复制构造函数。 可使用虚函数 Clone 模拟虚复制构造函数,但需要显式地调用 class Base { public: virtual Base* Clone() const = 0; }; class Derived: public Base

{ //…other members public: Base* Clone() const { return new Derived(*this); return new Derived that is a copy of this } };

编译器为何要创建虚函数表? 答:用于存储函数指针,确保调用正确的虚函数版本。

前缀递增运算符(++) Date& operator ++ () { //operator implementation code return *this; } 后缀递增运算符 Date& operator ++ (int) { //Store a copy of the current state of the object, before incrementing date Date Copy(*this); //operator implementation code (that increments this object) //return the state before increment was performed return Copy; } 转换运算符 例: 使用转换运算符将 Date 转换为 const char* 需包含的头文件 #include <sstream> #include <string> 实现函数 operator const char*() { //使用 std::ostringstream 将整型成员转换成一个 std::string 对象 ostringstream formattedDate; formattedDate << Day << “/” << Month << “/” << Year; //将其拷贝存储在私有成员 Date::DateInString(string 类型)中,因为 formattedDate 是一个局部变量,运算符返回时,通过 str()获得的指针无效。

DateInString = formattedDate.str(); return DateInString.c_str(); } 这样我们可以以新的方式使用 Date 类: string strHoliday (Holiday); //Compiler invokes operator const char* strHoliday = Date(11,11,2011);

智能指针 std::unique_ptr(类似于模板库中的智能指针类) 需包含头文件 #include <memory> //include this to use std::unique_ptr 实现方法 unique_ptr<int> pDynamicAllocInteger(new int); *pDynamicAllocInteger = 42; unique_ptr<Date> pHoliday(new Date(25,11,2011)); pHoliday->DisplayDate(); //(*pHoliday).DisplayDate();

下标运算符[] 例: const char& operator [] (int Index) const { if (Index < GetLength()) return Buffer[Index]; } 通过使用 const, 可禁止从外部通过运算符[]直接修改成员 MyString::Buffer 防止出现这样的 代码: MyString SayHello(“Hello World”); sayHello[2] = ?k?; //error: operator [] is const 还将运算符的函数类型设置成 const,这将禁止该运算符修改类的成员属性。 也可以实现两个下标运算符,一个为 const 函数,另一个为非 const 函数: char& operator [] (int nIndex); //use to write / change Buffer at Index char& operator [] (int nIndex) const; //used only for accessing char at Index

函数运算符 operator() class CDisplay { public: void operator () (string Input) const { cout << Input <<endl; }

}; int main() { CDisplay mDisplayFuncObject; mDisplayFuncObject(“Display this string!”); return 0; } 之所以能够将对象 mDisplayFuncObject 用作函数,是因为编译器隐式地将它转换为对函数 operator()的调用。

如果编写的类封装了一个动态整型数组,请问至少应该实现哪些函数和方法? 答:编写这样的类时,必须明确定义下述情形的行为:通过赋值直接复制对象或通过按值传 递给函数间接复制对象。通常,应实现复制构造函数、复制赋值运算符和析构函数。另外, 如果想改善这个类在某些情况下的性能,还应实现移动构造函数和移动赋值运算符。

C++提供了一种新的类型转换运算符,专门用于基于继承的情形(不要轻易使用) 4 个 C++类型转换符如下: · static_cast · dynamic_cast · reinterpret_cast · const_cast 使用语法: destination_type result = cast_type <destination_type> (object_to_be_casted); 使用 static_cast(在编译阶段检查) Base* pBase = new Derived(); //construct a Derived object Derived* pDerived = static_cast<Derived*>(pBase); //OK //CUnrelated is not related to Base via any inheritance hierarchy CUnrelated* pUnrelated = static_cast<CUnrelated*>(pBase); //Error //The cast above is not permitted as types are unrelated 将 Derived*转换为 Base*被称为向上转换,无需使用任何显式类型转换运算符就能进行 将 Base*转换为 Derived*被称为向下转换,如果不用显式类型转换符就无法进行 使用 dynamic_cast(在运行阶段执行转换) Base* pBase = new Derived(); //Perform a downcast Derived* pDerived = dynamic_cast <Derived> (pBase); if (pDerived) //Check for success of the cast. pDerived->CallDerivedClassFunction(); 将 Derived*传递给 Base*参数的函数时务必检查 dynamic_cast 的返回值,看它是否有效。

如果返回 NULL,说明转换失败。 使用 reinterpret_cast(强制重新解释) 只改变对指针的解释,并不改变指向的对象 Base* pBase = new Base(); CUnrelated* pUnrelated = reinterpret_cast<CUnrelated*>(pBase); 通常用于低级程序(如驱动程序) 使用 const_cast(关闭对象的访问修饰符 const) void DisplayAllData(const SomeClass& mData) { mData.DisplayMembers(); //Compile failure //reason for failure: call to a non-const member using a const reference } 可以使用 SomeClass& refData = const_cast<SomeClass&>(mData); 解除 const 限制,也可用于指针。但一般不要这么做,而是修改函数的 const。


赞助商链接

更多相关文章:
C++中一些基本概念
C语言第2讲-C语言基本概念 55页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 C++中一些基本概念 隐藏>> 1 浮...
C++基本概念
C语言基本概念 15页 7下载券 c语言基本概念 5页 2下载券 3-C#基本概念3 暂无...因此 C++语言便从 PL/I 语言中移植了异常处理的功能。异 常处理有三个部分...
C++基本概念
C++基本概念_计算机软件及应用_IT/计算机_专业资料 暂无评价|0人阅读|0次下载|举报文档 C++基本概念_计算机软件及应用_IT/计算机_专业资料。解释型语言和编译型...
c c++基本概念总结,笔试必考
c/ c++基本概念总结,笔试必考 基本概念总结, 基本概念总结 static 用法小结 static 关键字是 C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种只指...
C++考试基本概念
C++概念 10页 2财富值如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 C++考试基本概念 毕业论文毕业论文隐藏>> 1、类的...
3~C++基础概念
3~C++基础概念题_计算机软件及应用_IT/计算机_专业资料。第三章 1. A. B. C. D. 关于类和对象不正确的说法是( C ) 类是一种类型,它封装了数据和操作 ...
C++典型概念与习题
C++典型概念与习题 - C++典型概念与习题 一、基本概念 1. 在类体内定义的成员函数默认为内联函数,在类体外定义的成员函数只有用 inline 修饰的才可能成为内联...
6~C++基础概念
C++模板基础概念练习题 2页 免费 氧化还原反应概念(基础题) 3页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 ...
C++基本概念在编译器中的实现
C++基本知识C++基本知识隐藏>> C++基本概念在编译器中的实现对于C++对象模型,相信很多程序员都耳熟能详。 本文试图通过一个简单的例子演示一些 C++基本概念在编译器...
C++类与对象的基本概念
类与对象的基本概念 学院: 专业: 指导教师: 报告人: 学号: 班级: 实验时间: 实验报告提交时间: 教务处制 一、实验目的 类是 C++扩展数据类型,可以封装不同类...
更多相关标签:

All rights reserved Powered by 甜梦文库 9512.net

copyright ©right 2010-2021。
甜梦文库内容来自网络,如有侵犯请联系客服。zhit325@126.com|网站地图