•   写在前面
  • Object Oriented

class 的分类:带指针的class和不带指针的class,

class 的声明

       

这里有一个inline的概念,写在类里面的默认为inline,写在class外部的只有声明,为inline才有可能编译成Inline,最终编译时是否为inline,由编译器决定。Inline函数速度快.

public:

private:所有数据都应放在private,函数根据是否想要被外界调

使用对象

×   √ 

  • 构造函数:

想要创建一个对象,会自动调用的函数就是构造函数,如上,构造函数与类同名,没有返回类型,不需要有,因为构造函数就是要来创建对象的,此处对象就是complex,上面定义的构造函数使用了列表初始化,并且这种初始化只有构造函数才有,其它函数是没有的,并且给出了default argument

这里多说一些,一个数值的设定有两个阶段,一个是初始化,一个是后面再赋值(assign),所以列表初始化和在函数体赋值是不同的。

与构造函数对应是析构函数,但是这个例子中不需要写析构函数,前面提到过class的经典分类,不带指针的class多半需用写析构函数

构造函数可以有多个-overloading,但是存在歧义的不可以,如下:

  1. complex() :re(), im() {}//不可以,ambiguous

如下面的对象c2,都没有给参数,编译器发现 可以调用上面的,但是编译器也发现class中的构造函数虽然有参数,但是有默认值,也可以调用,因此编译器就不知调用哪个了

创建对象

       

构造函数放在private中,即不允许外界调用构造函数

  1. class A {
  2. public:
  3. static A& getInstance();
  4. private:
  5. A();
  6. A(const A& rhs);
  7.  
  8. };
  9.  
  10. A& A::getInstance()
  11. {
  12. static A a;
  13. return a;
  14. }

外界只能用一份A,即static的部分,外界用的时候不能使用传统的调用方式,只能通过getInstance()函数

  •  参数传递与返回值
  1. double real()const { return re; }
  2. double imag()const { return im; }

看上面的代码,都是const型的,因为我不需要改变数据,只是将数据拿出来,看下面两种情况

A.        B.

如果我的函数没用定义为const类型,B中的调用就是错误的,使用者本想,我只是返回数据,并不改变,所以创建了一个常对象,但是由于函数没有定义为const,所以就会出现调用错误。

  • 参数传递:

pass by value  vs pass by reference(to const)

pass by value 就是整包都传过去,数据多大就传多大,传的数据是压到static栈中的,本例中,传的是double,是4个字节,传的就是4个字节,若传的数据很大呢,效率就低,所以尽量不要pass by value,  可以pass by reference ,reference在底部就是指针,

  1. ostream& operator <<(ostream& os, const complex& x)
  2. {
  3. return os << '(' << real(x) << ',' << imag(x) << ')';
  4. }
  5. int main()
  6. {
  7. complex c1(, );
  8. complex c2;
  9. c2 += c1;
  10. cout << c2;
  11. }

第7,8行会调用构造函数,通过pass by lalue的方式,第9行会调用1-4行的函数,pass by reference的方式。返回值的传递也尽量pass by reference

  1. friend complex& __doapl(complex*, const complex&);//return value :pass by reference

后面会给出上面函数的detail

下面看一种情况,为什么可以这样使用

  1. int func(const complex& param)
  2. {
  3. return param.re + param.im;
  4. }
  5. //用法
  6. complex c3;
  7. c3.func(c1);

可以这样理解:相同class的各个objects 互为friends

class body外的各种定义什么情况下可以pass by value,什么情况下可以pass by reference

首先看看什么情况不能return by reference

  1. inline complex&
  2. __doapl(complex* ths, const complex& r)
  3. {
  4. ths->re += r.re;//第一参数将会被改动
  5. ths->im += r.im;//第二参数不会被改动
  6. return *ths;
  7. }
  8. inline complex&
  9. complex::operator+=(const complex& r)
  10. {
  11. return __doapl(this, r);
  12. }

这里,函数将结果放在第一个参数中,有专门的存储的空间,还有一种情况就是函数专门开辟一个空间存放结果,如果只是

  1. return c1 + c2;

这时,是一个临时开辟的local变量存储c1+c2的结果,函数结束,这个临时变量的生命就结束了,这时,就不能返回reference

  • 操作符重载(-1,成员函数) this

想象我们在数学中的复数,有哪些操作,比如相加,复数+复数,复数+实数,复数+纯虚数,

继续看上面代码,编译器看到c2+=c1,就会把操作符作用到左边c2身上,上面的inline complex& complex::operator+=(const complex& r){}相当于

inline complex& complex::operator(this,const complex& r){}

为什么可以这样呢,这就是上面辩题中写道的操作符重载之成员函数,因为所有成员函数带有一个隐藏的参数this,谁调用这个函数谁就是this,这里this是c2,

Note:this不可以写在参数列表中,用可以像函数体中那样用,return __doapl(this,r);

  • return by reference 语法分析

继续看上面的代码,看函数定义时的返回类型是complex&,函数体内返回的却是*ths,这样是正确的,因为,传递者无需知道接收者是以reference形式接收

class body之外的函数定义

operator overloading(操作符重载-2,非成员函数)无this

考虑到用户的行为,定义了三种+ 形式

  1. inline complex
  2. operator +(const complex& x, const complex& y)
  3. {
  4. return complex(real(x) + real(y), imag(x) + imag(y));
  5. }
  6.  
  7. inline complex
  8. operator +(const complex& x, double y)
  9. {
  10. return complex(real(x) + y, imag(y));
  11. }
  12.  
  13. inline complex
  14. operator +(double x, const complex& y)
  15. {
  16. return complex(x + real(y), imag(y));
  17. }

如上,对于上面的操作符重载,没有this pointer,因为是全域函数,不再是成员函数

  • temp object (临时对象)tempname()

再看上面的代码,return by value,对于上面的代码,绝不可以return by reference,因为他们返回的一定是local object,因为加的结果是函数临时创建的,函数结束,临时变量死亡,

解释一下:tempname(),此处是complex(),就是创建临时对象,tempname()类似于Int(),

  1. operator +(const complex& x)
  2. {
  3. return x;
  4. }
  5.  
  6. inline complex
  7. operator -(const complex& x)
  8. {
  9. return complex(-real(x), -imag(x));
  10. }
  11. //使用
  12. {
  13. complex c1(, );
  14. complex c2;
  15. cout << -c1;
  16. cout << +c1;
  17. }

这里是return  by value,这里可是return by reference,因为,这里结果没有改变,也没有创建新的临时对象,所以是可以return by reference的。

接下来还是操作符重载,考察的东西一样,语法上没有新的了,

  1. inline bool
  2. operator ==(const complex& x, const complex& y)
  3. {
  4. return real(x) == real(y) && imag(x) == iamg(y);
  5. }
  6. inline bool
  7. operator ==(const complex& x, double y)
  8. {
  9. return real(x) == y && iamg(x) == ;
  10. }
  11.  
  12. inline bool
  13. operator ==(double x, complex& y)
  14. {
  15. return x == real(y) && iamg(y) == ;
  16. }
  17.  
  18. inline bool
  19. operator !=(const complex& x, complex& y)
  20. {
  21. return real(x) != real(y) || imag(x) != imag(y);
  22. }
  23.  
  24. inline bool
  25. operator !=(const complex& x, double y)
  26. {
  27. return real(x) != y || iamg(x) != ;
  28. }
  29.  
  30. inline bool
  31. operator !=(double x, complex& y)
  32. {
  33. return x != real(y) || iamg(y) != ;
  34. }
  35.  
  36. inline complex
  37. conj(const complex& x)
  38. {
  39. return complex(real(x), -imag(y));
  40. }
  1. ostream& operator <<(ostream& os, const complex& x)
  2. {
  3. return os << '(' << real(x) << ',' << imag(x) << ')';
  4. }
  5.  
  6. //使用
  7. {
  8. cout << conj(c1);
  9. cout << c1 << conj(c1);
  10. }

"<<"作用在左边,这里绝不能写成成员函数,必须写成全域函数。os也不可是const的,因为每往cout中放入“东西”的时候都是在改变os中的内容,若将返回类型 ostream& ,改为 void 可以吗?

如果只是输出一个是可以的(上面第一处使用),如果连续输出是不可以的(第二处使用),

下面是完整的代码(还有很多操作没写,但写的已经涵盖了这种类型的class的几乎所有语法,有时间再补全):

  1. #pragma once
  2. #ifndef __COMPLEX__
  3. #define __COMPLEX__
  4.  
  5. class complex {
  6. public:
  7. complex(double r = , double i = ) :re(r), im(i) {}//construct function
  8. //complex() :re(0), im(0) {}//不可以,ambiguous
  9. complex& operator +=(const complex&);//two choices,member func or non-member func,
  10. //here is member func,do not need to change the value,so is const
  11. double real()const { return re; }
  12. double imag()const { return im; }
  13. int func(const complex& param)
  14. {
  15. return param.re + param.im;
  16. }
  17. private:
  18. double re, im;
  19. friend complex& __doapl(complex*, const complex&);//return value :pass by reference
  20.  
  21. };
  22.  
  23. inline complex&
  24. __doapl(complex* ths, const complex& r)
  25. {
  26. ths->re += r.re;//第一参数将会被改动
  27. ths->im += r.im;//第二参数不会被改动
  28. return *ths;
  29.  
  30. }
  31. inline complex&
  32. complex::operator+=(const complex& r)//the right is not change,so is const,the left
  33. {//has already existed,so return by reference
  34. return __doapl(this, r);
  35. }
  36. inline double
  37. real(const complex& x)
  38. {
  39. return x.real();
  40. }
  41. inline double
  42. imag(const complex& x)
  43. {
  44. return x.imag();
  45. }
  46. //"+"has more than one cases,so set it as the non-member func
  47. inline complex
  48. operator +(const complex& x, const complex& y)
  49. {//the sum result will be put in a local variable,so return by value
  50. return complex(real(x) + real(y), imag(x) + imag(y));
  51. }
  52.  
  53. inline complex
  54. operator +(const complex& x, double y)
  55. {
  56. return complex(real(x) + y, imag(y));
  57. }
  58.  
  59. inline complex
  60. operator +(double x, const complex& y)
  61. {
  62. return complex(x + real(y), imag(y));
  63. }
  64. inline complex
  65. operator +(const complex& x)
  66. {
  67. return x;
  68. }
  69.  
  70. inline complex
  71. operator -(const complex& x)
  72. {
  73. return complex(-real(x), -imag(x));
  74. }
  75.  
  76. inline bool
  77. operator ==(const complex& x, const complex& y)
  78. {
  79. return real(x) == real(y) && imag(x) == imag(y);
  80. }
  81. inline bool
  82. operator ==(const complex& x, double y)
  83. {
  84. return real(x) == y && imag(x) == ;
  85. }
  86.  
  87. inline bool
  88. operator ==(double x, complex& y)
  89. {
  90. return x == real(y) && iamg(y) == ;
  91. }
  92.  
  93. inline bool
  94. operator !=(const complex& x, complex& y)
  95. {
  96. return real(x) != real(y) || imag(x) != imag(y);
  97. }
  98.  
  99. inline bool
  100. operator !=(const complex& x, double y)
  101. {
  102. return real(x) != y || imag(x) != ;
  103. }
  104.  
  105. inline bool
  106. operator !=(double x, complex& y)
  107. {
  108. return x != real(y) || imag(y) != ;
  109. }
  110.  
  111. inline complex
  112. conj(const complex& x)
  113. {
  114. return complex(real(x), -imag(x));
  115. }
  116.  
  117. #endif

测试代码有时间再补

C++ class without pointer members的更多相关文章

  1. C++类设计2(Class with pointer members)

    二 Class with pointer members(Class String) 1. 测试代码(使用效果) int main() { String s1(), String s2("h ...

  2. C++类设计1(Class without pointer members)

    class complex{ public: complex (double r = 0, double i = 0):re(r), im(i){} //inline complex& ope ...

  3. C++Primer 5th 练习 12.19

    这阵子真是太忙了, 连续做了四个课设. 当然这并不能作为好久没写博客的借口, 没写博客的主要原因只有一个: 懒. 最近又开始回顾C++的语法与特性(据说C++就是一门需要反复回顾的语言),以及学习C+ ...

  4. Google C++ Style Guide

    Background C++ is one of the main development languages used by many of Google's open-source project ...

  5. 4、Type fundamentals

    1.All Types Are Derived from System.Object The CLR requires all objects to be created using the new ...

  6. C and C++ : Partial initialization of automatic structure

    Refer to: http://stackoverflow.com/questions/10828294/c-and-c-partial-initialization-of-automatic-st ...

  7. [转] 关于c++的头文件依赖

    http://www.cnblogs.com/yvesliao/p/3938730.html PS: 使用单向依赖 正在看google c++编程规范,里面对头文件依赖是这么说的: 1 2 3 4 5 ...

  8. Google C++ 代码规范

    Google C++ Style Guide   Table of Contents Header Files Self-contained Headers The #define Guard For ...

  9. What is The Rule of Three?

    Question: What does copying an object mean? What are the copy constructor and the copy assignment op ...

随机推荐

  1. Linux03——磁盘分区和挂载

    Windows下的磁盘分区: 常用的两种磁盘分区类型 mbr: 操作系统安装在主分区 只支持4个主分区 拓展分区占一个主分区 gpt(win7 64位之后) 无限主分区 支持超大硬盘3T以上 查看所有 ...

  2. window下载并且安装kafka

    安装zookeeper kafka运行需要有jdk+zookeeper环境才能够使用,jdk的安装和环境变量的配置就不介绍了,这里需要先安装zookeeper.可以从官网上下载 https://www ...

  3. 解决VMware Workstation下Win2012R2无法安装Hyper-v问题

    有时候我们需要测试Hyper-V但是发现VMware下不能够正常安装,提示:验证过程发现你要安装功能的服务器存在问题.所选功能与所选服务器的当前配置不兼容.无法安装Hyper-V:虚拟机监控程序已在运 ...

  4. PTA的Python练习题(十八)

    第4章-20 求矩阵各行元素之和 遇到一个麻烦的事情: 上面a,b输入,如果一起输入转int会报错,因为int只能一对一 但是明明我分开来int了,下面第十行还是报错说我的b是string字符,难不成 ...

  5. 台电X16pro刷机记录

    Android: 如果要刷安卓,需要使用win7系统电脑,且需要安装java环境,同时按住 音量减+电源键进入刷机模式(DNX BOOT MODE..),这时在PhoneFlashTool_5.3.2 ...

  6. ST股

    一.简介: 意即“特别处理”.该政策针对的对象是出现财务状况或其他状况异常的. 1998年4月22日,沪深交易所宣布,将对财务状况或其它状况出现异常的上市公司股票交易进行特别处理(Special tr ...

  7. 从0到1了解 CI/CD

    现代软件开发的需求加上部署到不同基础设施的复杂性使得创建应用程序成为一个繁琐的过程.当应用程序出现规模性增长,开发团队人员变得更分散时,快速且不断地生产和发布软件的流程将会变得更加困难.为了解决这些问 ...

  8. Java常量/变量

    1. 常量 /* 常量:在程序运行期间,固定不变的量. 常量的分类: 1. 字符串常量:凡是用双引号引起来的部分,叫做字符串常量.例如:"abc"."Hello" ...

  9. Python使用Tensorflow出现错误: UserWarning: The default mode, 'constant'

    Python使用Tensorflow出现错误: UserWarning: The default mode, 'constant', will be changed to 'reflect' in s ...

  10. 在C中测试函数运行时间

    #include <stdio.h> #include <time.h> #include <math.h> clock_t start, stop; //cloc ...