1.头文件与类的声明

c++关于数据的函数

相较于c的特点:class和struct

以上两种形式创建了objects

c与c++形式上的对比

本课程以complex和string为例:

正式开始之前:代码基本形式

c++代码主要由以下三部分组成:

c和c++的输出的区别

c++的优势是cout啥都可以丢!

头文件正规写法:防御声明

同一个程序第二次include就不会再次引入,否则会形成无限循环!

很重要的防卫声明。

头文件正规写法:布局

最主要的是1和2,然后写完再检讨声明0;

class的声明

每一个class都有一个head,再加上body!

实部虚部是一个double值,要设计另一个复数是整数或者float怎么办?

class的模板:解决重复性

T可以随意替换,第一行告诉编译器啥是T,下面的为实例指定double或者int。

有很多函数,不过多着墨。可以自行了解

2.构造函数

inline函数

inline拥有很大的优势,速度很快!但是是否inline由编译器决定!

不在本体内定义就可以加inline

访问级别

public可以被外界看到,private就要封装起来!

不必非得集中为2段。

下面的两个就是调用函数。

重要数据要放在private!

构造函数是什么?

构造函数写法很独特,函数名要和class名一样,然后括号里传入参数(默认实参)。

并且构造函数不需要有返回值,因为构造函数就是用来创建对象的。

有些人可能在大括号里赋值,但是要培养大气的写法:

complex (double r = 0, double i = 0)
: re (r), im (i) 

这种写法只能在构造函数里写,原理和re=r一样,但是为什么要在这里做?

简单来说一个变量数值的设定有初始化和赋值,第一阶段是: re (r), im (i),初始化就会效率高一些。

传进来的实参要赋值给别人,不然的话传进来的实参就会消失在构造函数里面!

3.参数传递与返回值

构造函数可以有很多个-重载

比如说设计一个类,有很多种想法,所以就可以重载。

为什么可以重载?

编译器会把函数编译成如右下角的东西,所以名称并不相同。

如果函数有默认函数,则和无参数同名参数重复了,如上1和上2,complex()不知道调用哪个。

把构造函数放在private区

class complex
{
public:

complex& operator += (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
double re, im;
complex (double r = 0, double i = 0)
: re (r), im (i) 
{ }
friend complex& __doapl (complex*, const complex&); 

};

如上所示如果把构造函数放在private就不可以进行如下操作了:

{

complex c1(2,1);
complex c2;
...

}

什么情况可以放在private里?

在经典设计模式 singleton中,把构造函数放在了private里:

class A {
public:
static A& getInstance();
setup() { ... }
private:
A();
A(const A& rhs);
...
};

A& A::getInstance()
{
static A a;
return a;
}

外界可以通过A::getInstance().setup();来进行调用其中的getinstance函数。

常量成员函数

即再函数的后面加const:

class complex
{
public:
complex (double r = 0, double i = 0)
: re (r), im (i) 
{ }
complex& operator += (const complex&);
double real () const { return re; } //在这里
double imag () const { return im; }
private:
double re, im;

friend complex& __doapl (complex*, const complex&); 

};

real和imag不改变数据,则马上加上const。

如果不加的话,使用者如下这么使用的话:

{

const complex c1(2,1);
cout << c1.real();
cout << c1.imag();

}

使用者:不改data,函数:可以改data

这样的话使用者就会被禁止使用const,使得使用者很生气(?

参数传递 by value or by reference

整包传过去,把整个值挪过去!

所以尽量reference。

之前c可以传指针,现在可以用引用!

如果传过去不希望对方改,加const。

返回值传递:by value or by reference

返回值也尽量传reference

什么时候不可以返回reference?

image-20211221203616723

两种情况,ths加上了传进来的r,ths这个空间本来就在的,如果说在函数里构造了变量,返回了reference,等执行完毕这个引用就被销毁了,白玩!

友元

image-20211221202913512

声明一个朋友,这个朋友可以自由取得friend的private成员!

相同的class的各个objects互为friends(友元)

4.操作符重载与临时对象

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

c2+=c1的理解,+=作用于c2

所有的成员函数一定带一个隐藏的参数this,谁调用函数谁就是this,此时this为c2的指针,不能在参数列写出来,但是在函数里可以用!

return by reference 语法分析

传进来的左操作数是一个指针,返回一个object,可是返回的声明是complex&,是无所谓的,传递者无需知道接收者是以reference形式接收。

如果使用者这么用:c2+=c1,inline void是可以的,但是如果使用c3+=c2+=c1,就不可以返回void了。

class body之外的各种定义

操作符重载-2,非成员函数

temp object(临时对象) typename()

上图绝不可return by reference。因为他们的返回必定是个local object!

typename生命很短,无需命名。

各种操作符重载,非成员函数

查手册发现cout为ostream参数,每一次输出都在改变,所以ostream不能加const。

因为可能涉及<<xx<<xx这么输出,所以返回类型应该设置为ostream

复习

#ifndef _COMPLEX_
#define _COMPLEX_
class complex;
class complex& __doapl(complex*, const complex&);
class complex
{
public:
  complex(double r = 0, double i = 0)
    :re(r), im(i) //只需要经过一步编译就可返回,很好用!
  {};
  complex& operator += (const complex&);
  double real() const { return re; }
  double imag() const { return im; }


private:
  double re, im;
  friend complex& __doapl(complex*, const complex&);

};
inline complex&
__doapl(complex* ths, const complex& r)
{
  ths->re += r.re;
  ths->im += r.im;
  return *ths;
}
//because right could be change and can abundant, so add const 
inline complex& complex::operator += (const complex& r) {
  return __doapl(this, r);
} //only write right 

inline double
imag(const complex& x)
{
  return x.imag();
}

inline double
real(const complex& x)
{
  return x.real();
}

inline complex
operator + (const complex& x, const complex& y)
{
  return complex (real (x) + real (y), imag (x) + imag (y));
}
//why not design  member function,because complex + true number
inline complex
operator + (const complex& x, double  y)
{
  return complex(real(x) + y, imag(x));
}//why not design  member function,because complex + true number
inline complex
operator + (double x, const complex& y)
{
  return complex(x + real(y), imag(y));
}//why not design  member function,because complex + true number

#include 
std::ostream& //back add ostream
operator << (std::ostream& os, const complex& x) //cout will change
{
  return os << '(' << real(x)  << ',' << imag(x) << ')';
}
#endif

注意事项与整理:

  • 设计一个class构造函数:re(r)要用起来
  • 函数加不加const一定要考虑
  • 参数传递一定要考虑&
  • return要不要&
  • 数据尽可能的放在private,函数放在public