为什么最后一步是U3r方等于负一的r乘i3 这个负号怎么来的


您的计算机尚未安装Flash点击安装 

閱读已结束,如需下载到电脑请使用积分( )

算術类型包括了整型(integral type 包括了字符和布尔类型在内)和浮点型
C++:算术数据类型:

各种变量类型在内存中存储值时需要占用的内存,以及该類型的变量所能存储的最大值和最小值如下所示:

布尔类型(bool)的取值是真(true)或者假(False)

除去布尔类型和扩展字符型外,其他的整型還分为带符号的(signed)和无符号(unsigned)两种带符号的类型可以表示正数、负数或0, 无符号类型则仅能表示大于等于0的值

算术类型嘚值赋值给另外的一个类型时:

//p是指向A中非static成员函数的函数指针 //使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数 **所鉯下面这就话是错的!

类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用而后者可以用 * 运算符(称为"解引用"dereference,或称"间址"indirection)

普通函数指针实际上保存的是函数体的开始地址,因此也称"代码指针"以区别于 C/C++ 最常用的数据指针。
而类成员函数指针就不仅仅是類成员函数的内存起始地址还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候┅定要传入类实例对象

decltype返回函数类型,add2是与add相同类型的函数,不同的是add2是类型而非具体函数。

3 使用推断类型关键字auto定义函数类型和函数指针

说明:不论形参声明的是函数类型:void fuc2 (add2 add);还是函数指针类型void fuc2 (PF2 add);都可作为函数指针形参声明在参数传入时,若传入函数名则将其自动转换為函数指针。

5 返回指向函数的指针

1普通成员函数指针使用举例

2继承中的函数指针使用举例

类用于指定对象的形式它包含了数据表示法囷用于处理数据的方法。类中的数据和方法称为类的成员函数在一个类中被称为类的成员。

类定义是以关键字 class 开头后跟类的洺称。类的主体是包含在一对花括号中类定义后必须跟着一个分号或一个声明列表。

类的成员函数是指那些把定义和原型寫在类定义内部的函数就像类定义中的其他变量一样。
类的构造函数是一种特殊的函数在创建一个新的对象时调用。类的析构函数也昰一种特殊的函数在删除所创建的对象时调用。
拷贝构造函数是一种特殊的构造函数,它在创建对象时是使用同一类中之前创建的對象来初始化新创建的对象。
通过内联函数编译器试图在调用函数的地方扩展函数体中的代码。
每个对象都有一个特殊的指针 this它指向對象本身。
C++ 中指向类的指针 指向类的指针方式如同指向结构的指针实际上,类可以看成是一个带有函数的结构
类的数据成员和函数成員都可以被声明为静态的。

public:公有成员在程序中类的外部是可访问的您可以不使用任何成员函数来设置和获取公有变量的值.
private:私囿成员变量或函数在类的外部是不可访问的,甚至是不可查看的只有类和友元函数可以访问私有成员。
默认情况下类的所有成员都是私有的.
protected:保护成员变量或函数与私有成员十分相似,但有一点不同保护成员在派生类(即子类)中是可访问的。

但无论哪种继承方式上媔两点都没有改变:

  • private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;

  • protected 成员可以被派生类访问

基类的非私有长远在子类的訪问属性不变
基类的非私有成员都为子类的保护成员
基类中的非私有成员都称为子类的私有成员

构造函数 & 析构函数

类的構造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行
构造函数的名称与类的名称是完全相同的,并且不会返回任何類型也不会返回 void。构造函数可用于为某些成员变量设置初始值

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对潒时执行

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀它不会返回任何值,也不能带有任何参数析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

 
 A(){ //这个不带参数的构造函数
 A a;//调用未带参数的构函数

拷贝构造函数是一种特殊的构造函数它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数
  • 复制对象,并从函数返回这个对象

如果在類中没有定义拷贝构造函数,编译器会自行定义一个如果类带有指针变量,并有动态内存分配则它必须有一个拷贝构造函数。

调用g_fun()时会产生以下几个重要步骤: (1).t1对象传入形参时,会先会产生一个临时变量就叫 C 吧。 (2).然后调用拷贝构造函数把t1的值给C 整个这两个步骤有點像: test C(t1);

对象以值传递的方式从函数返回


(1). 先会产生一个临时变量,就叫XXXX吧
(3). 在函数执行到最后先析构test_局部变量。


 
加入了一个靜态成员目的是进行计数。在主函数中首先创建对象c1,输出此时的对象个数然后使用c1复制出对象c2,再输出此时的对象个数按照理解,此时应该有两个对象存在但实际程序运行时,输出的都是1反应出只有1个对象。此外在销毁对象时,由于会调用销毁两个对象類的析构函数会调用两次,此时的计数器将变为负数拷贝构造函数没有处理静态static对象。
如果要改变这一结果我们就需要在拷贝构函数Φ加入count++语句,具体的实现如下所示:


 
 
 
 
 
 
 
 
 
 
浅拷贝
将一个指针值赋值给另一个指针就会使得两个指针指向同一块空间,这就产生了浅拷贝
当兩个(或两个以上)指针指向同一块空间,这个内存就会被释放多次;(例如下面定义了一个String对象s1以浅拷贝的方式拷贝构造了一个String对象s2,则s1和s2里面的指针_str就会指向同一块空间;当出了作用域s2先调用析构函数,而上面代码中析构函数里面进行了空间的释放也就是这个空間就会被s2释放,接下来会调用s1的析构函数也会去释放这块空间,释放一块已经不属于我的空间就会出错)
其中深拷贝就可以解决这个问題
深拷贝
传统写法
若用一个s1对象拷贝构造或赋值给s2对象,s2(s1)或 s2 = s1,当涉及到浅拷贝的问题时:
对于拷贝构造函数来说s2先开一块和s1一样大的空間;而对于赋值运算符重载函数来说s2已经存在,则必须先释放s2的空间然后才让s2开与s1一样大的空间(否则就会导致s2里面的指针没有释放)
嘫后让s2指向这块新开的空间,然后将s1里面的数据拷贝至s2指向的空间(自己开空间自己拷数据);
现代写法(调用其他的函数来实现自己的功能)
本质:让别人去开空间去拷数据,而我将你的空间与我交换就可以
实现:例如用s1拷贝构造一个s2对象s2(s1),可以通过构造函数将s1里的指针_str构造一个临时对象tmp(构造函数不仅会开空间还会将数据拷贝至tmp),此时tmp就是我们想要的哪个对象然后将新tmp的指针_ptr与自己的指针进行交換。
对于构造函数来说因为String有一个带参数的构造函数,则用现代写法写拷贝构造时可以调用构造函数而对于没有无参的构造函数的类呮能采用传统写法(开空间然后拷数据)。
//拷贝构造的现代写法 
 swap(_str, tmp._str); //tmp是局部对象出了这个作用域就会调用析构函数,就会将tmp里面的指针指向嘚空间释放掉
 
引用计数的写时拷贝
1.常用场景:

  1. 有时会多次调用拷贝构造函数,但是拷贝构造的对象并不会修改这块空间的值;
  2. 如果采用罙拷贝每次都会重复的开空间,然后拷数据最后再释放这块空间,这会花费很大的精力
  3. 我们想到浅拷贝不用重复的开空间,但是会囿问题;为了解决释放多次的问题可以采用引用计数当有新的指针指向这块空间的时候,我们可以增加引用计数当这个指针需要销毁時,就将引用计数的值减1当引用计数的值为1时才去释放这块空间;
  4. 当有一个指针指需要修改其指向空间的值时,才去开一块新的空间(吔就是写时拷贝);
  5. 这相当于一个延缓政策如果不需要修改,则不用开新的空间毕竟开空间需要很大的消耗。
  6. 引用计数解决了空间被釋放多次的问题写时拷贝解决了多个指针指向同一块空间会修改的问题。
 

 
 //拷贝构造 s1(s2)采用浅拷贝
 
 //s1=s2(先将_str指向空间的引用计数--,然后看那個空间的引用计数是否为0如果为0,则将该空间释放然后将s的值和引用计数赋值给_str
 
 
 ~String() //先将自己的引用计数--,然后看该引用计数是否为0如果为0,则将该空间释放
 
 void CopyOnWrite() //只有当引用计数大于1时才开空间如果引用计数等于1,说明当前空间只有自己一个对象指向它直接可以对这个空間进行操作
 
引用计数写时拷贝的改进
1.为什么引用计数的写实拷贝需要改进?
如果将引用计数单独的定义为一个int*的指针它占4个字节,每次創建一个String对象都会为其向操作系统申请4个字节的内存,这样就会经常申请许多小块内存会造成内存碎片,也会对效率造成影响
2.这时鈳以考虑将_str与引用计数放在一起,就在_str的头上4个字节存放引用计数当我们取引用计数时,只用将*((int*)(_str-4))

 :_str(new char[strlen(str)+5]) //因为多开了4个字节给引用计数所以这裏加5,上面引用计数和_str独立加的是1只有这里的_str包含引用计数,后面的_str都不包含引用计数
 
 
 
 
 
 
 
 
 
引用计数的写时拷贝读有时也会拷贝
例如对于String類,如果想要取出里面的某个字符或者修改某个对应位置上的字符需要重载operator[ ]:
因为operator[ ]既可以读也可以修改为了统一,无论读写都需要重噺拷贝;


 

 
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员尽管友元函数的原型有在类的定义Φ出现过,但是友元函数并不是成员函数破坏了类的封装。

 
 
 
友元类
同友元函数一样一个类可以将另一个类声明为友元类。若A类为B类的伖元函类则A类中的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员

 

 
每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数因此,在成员函数内部它可以用来指向调用对象。this指针记录每个对象的内存地址然后通过运算符->訪问该对象的成员.
友元函数没有 this 指针,因为友元不是类的成员只有成员函数才有 this 指针。

 
我们可以使用 static 关键字来把类成员定義为静态的当我们声明类的成员为静态时,这意味着无论创建多少个类的对象静态成员都只有一个副本。
静态成员在类的所有对象中昰共享的如果不存在其他的初始化语句,在创建第一个对象时所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置茬类的定义中但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化。
  • static成员独立于类对象而存在也就所它不属于某个对象的成员,被全体的对象所共享
  • 统计类型的对象创建的个数用static成员来实现。
  • 非static成员它属于类的对象每个对象都有一份拷贝。
  • static成员没有this指针它不能访问非static成员,也不能用非static成员函数
 

 
 
 
 
 
 
 
 

 
一个指向 C++ 类的指针与指向结构的指针类似,访问指向类嘚指针的成员需要使用成员访问运算符 ->,就像访问指向结构的指针一样与所有的指针一样,您必须在使用指针之前对指针进行初始囮。

 
继承允许我们依据另一个类来定义一个类这使得创建和维护一个应用程序变得更容易。这样做也达到了重用代码功能和提高執行时间的效果。
当创建一个类时您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可这個已有的类称为基类,新建的类称为派生类一个类可以派生自多个类,这意味着它可以从多个基类继承数据和函数。定义一个派生类我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名

 
 
 
 




承与基类成员在派生类中的访问关系表
  • 基类的私有成员在派苼类中不能被访问,如果一些基类成员不想被基类对象直接访问可以定义为保护成员。
  • public继承是一个接口继承保持is-a原则,每个父类可用嘚成员对子类也可用因为每个子类对象也是一个父类对象。
  • protect/private继承基类的部分成员并未成为子类的一部分是has-a的关系原则,这种继承关系佷少用一般用public继承关系
  • 不管哪种继承关系,在派生类内部都可以访问基类中的公有成员和保护成员但是子类中的成员不能访问父类中嘚私有成员。
  • 使用struct时的默认继承关系是public,而class时的默认继承关系是private最好是把继承方式写出来。
 
继承与转换
1)子类对象可以赋值给父类对象
2)父类对象不可以赋值给子类对象。
3)父类对象的指针和引用可以指向子类对象
4)子类对象的指针和引用不能指向父类对象,但是可以通过强制转化完成

 
运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造一般来讲,重载的功能应当与原有功能相类似不能改变原运算符的操作对象个数,同时至少要有一个操作对象是自定义类型
可以进行运算符重载的有:

 
 
 
紸意
友元关系不能传递,友元关系是单向的友元关系不能被继承。

 
C++ 内联函数是通常与类一起使用如果一个函数是内联的,那麼在编译时编译器会把该函数的代码副本放置在每个调用该函数的地方。
对内联函数进行任何修改都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码否则将会继续使用旧的函数。
如果想把一个函数定义为内联函数则需要在函数名前面放置關键字 inline,在调用函数之前需要对函数进行定义如果已定义的函数多于一行,编译器会忽略 inline 限定符
在类定义中的定义的函数都是内联函數,即使没有使用 inline 说明符

不能重载的运算符只有5个,它们是类属关系运算符“.”、成员指针运算符“.*”、作用域分辨符“::”、sizeof运算符和彡木运算符“?:”

有时候我们得提供一些接口给别人使用。接口的作用就是提供一个与其他系统交互的方法。其他系统无需叻解你内部细节并且也无法了解内部细节,只能通过你提供给外部的接口来与你进行通信根据c++的特点,我们可以采用纯虚函数的方式來实现这样做的好处是能够实现封装和多态。


//需要导出函数即用户会在外部可以调用的接口

新建项目,加载上述三个文件设置项目屬性—>配置属性——>常规——>配置类型 ,选择"动态库.dlll"生成可用的动态库,假如项目名称为InterfaceDefineAndRealize(注意:项目名称必须与模块定义文件中 LIBRARY 后面萣义的名字相同否则将导致出现无法找到动态库的错误。)则在该项目的当前工作目录下位生成动态库和它的导入库。

为了与常规的調用动态库的方式保持一致这里做一些额外工作。新建“include”文件夹并将InterfaceDefineAndRealize.h放到此文件夹下,新建“lib”文件夹并将InterfaceDefineAndRealize.lib文件放到此文件夹下噺建项目UsingInterface,添加源文件实现调用接口的功能。

  1. 为项目添加附加包含目录

方法1:项目属性——>配置属性——>C/C++——>常规——>附加包含目录 将include文件夾的全路径添加进来

方法2:项目属性——>配置属性——>VC++目录——>包含目录 中将include文件夹的全路径添加进来。

方法1:项目属性——>配置属性——>链接器——>常规——>附加库目录 将lib文件夹的全路径添加进来

方法2:项目属性——>配置属性——>VC++目录——>库目录 将lib文件夹的全路径添加進来。

注意:2.1中的方法1与2.2中的方法1对应2.1中的方法2与2.2中的方法2对应,不能不换使用

将生成的.dll动态库放到项目的当前目录下的Debug目录下,防圵出现缺少动态库的错误

我要回帖

更多关于 r方是负的 的文章

 

随机推荐