目录标题
1.C++程序代码的基本形式
1.1 C++文件类型
- . h文件:
- 头文件:声明;
- 标准库.
- .cpp
- 主体
1.2头文件的正规写法
- 防卫式声明
#ifndef _COMPLEX_ //如果之前没有引用,第一次引用顺利往下
#define _COMPLEX_ //定义 _COMPLEX_
...
#endif
1.3内联函数 inline
函数在类的本体里定义,就形成inline .很快很好,但是函数太复杂无法inline。
如下,real()和imag都在本体里定义,为inline,
class complex //class head
{ //class body
public:
comlpex(double r=0, double i=0)
: re (r), im(i)
{}
complex& operator += (const complex&);
double real () const{ return re; }//此两函数有大括号{},即在此处定义
double imag () const{ return im; }
pravite:
double re, im;
friend complex&_doapl(copmlex*, const complex&);
};
{
complex c1(2, 1);
complex c2;
...
}
还可以使用关键字定义
inline double imag(const complex& x)
{
return x.imag();
}
1.4 访问级别
public :一般是函数,外界需要使用
private:一般是数据部分
还有protected 待续
使用:
正确,使用函数
{
complex c1(1 ,2);//
cout<<c1.real();
cout<<c1.imag();
}
错误,数据是private
{
complex c1(1 ,2);//
cout<<c1.re;
cout<<c1.im;
}
1.5构造函数
1.5.1想要创建一个对象,则自动调用
{
complex c1(2,1);
complex c2;//使用构造函数的默认值
complex* p = new complex(4);
}
1.5.2语法:
comlpex(double r=0, double i=0)
: re (r), im(i)//初始化方法,仅构造函数可以使用,本体不再使用赋值的方法
{}
- 构造函数可以重载
但是以下为错误调用:
complex(double r=0, double i=0) : re (r), im(i)
complex() : re(0) ,im(0);
...
{
complex c1;
complex c2();
}
//此时,c1为无参数,两个构造函数均可以调用,出现错误,因为第一个已经有默认值,两者冲突
1.5.3构造函数priave形式–单例 singleton
class A
{
public :
static A& getInstance();
setup(){...};
private:
A();
A(const A&rhs);
}
A& A::getInstance()
{
static A a;
return a;
}
单例外界只可以使用一份,如果想要调用A :: getInstance ().setup();
1.6常量成员函数与参数传递和返回值传递
class里的函数,有会改变数据内容的和不改变数据内容的,如果是不改变的,加上const,如下,仅仅是取数据。不改变double re,im;
double real () const{ return re; }//此两函数有大括号{},即在此处定义
double imag () const{ return im; }
如果上代码忘记写const,但是构造的变量却使用的const const complex c1(1,2)
则矛盾
构造时数据不可以改但是函数部分没了const又表名可以改,bug了,不可以使用c1.real() (没有const的版本);
pass by value、pass by reference和pass by reference to const
- pass by value:传递数值,整个数值,所有内容都传递出去,字节数相同,不建议使用。
complex( double r=0 ,double i=0): re(r), im(i) { }
- pass by reference:传递引用,引用的底部就相当于一个指针,传递速度很快。
ostream&
operator << (ostream& os,const complex& x)
{
return os << '('<<real(x)<<","<<imag(x)<<')';
}
- pass by reference to const:传递的引用不可以被修改
complex& operator += ( const complex& );
- 返回值也尽可能的return by reference,但是有情况不可以使用
比如做加法,c1 + c2,结果可以用两种方式保存, c1 += c2,直接放进c1里,另外一种是在函数中新建一个变量, c3 = c1 + c2,后者不可以返回引用。因为C3是一个Local型,函数结束则释放,不可以再传引用
传输者无需知道接受者以reference形式接收
例如在
{
complex c1(2,1);
complex c2(5);
c2 += c1;
}
inline complex&
_doapl(complex* ths,const complex& r)
{
ths -> re += r.re;
ths -> im += r.im;
return *ths;
}
incline complex&
complex :: operator += (const complex& r)
{
return __doapl(this, r);
}
按理来说,__doapl执行完返回是一个指针型,但是内联函数operator却是返回 complex&型,不冲突,在c2 += c1
返回什么值不重要,接收就行,返回void也正确。
但是如果为c3 += c2 += c1
先将c1,c2相加,值返回,再加到c3上,这里就必须返回
1.7友元
friend complex& _doapl(complex*,const complex&)
这样调用class中的private数据可以直接使用
inline complex&
_doapl(complex* ths,const complex& r)
{
ths -> re += r.re;
ths -> im += r.im;
return *ths;
}
相同class的各个object互为友元
class complex
{
public:
complex( double r=0 ,double i=0): re(r), im(i) { }
int func(const complex& param ){return param.re + param.im ;}
//很神奇,param可以直接访问私有的re 和 im
}
使用
{
complex c1(2, 1);
complex c2;
c2.func(c1);
}
1.8操作符重载
1.8.1成员函数重载 1 this
先看下面的代码。这个 c2 += c1的本质要理解。 += 本质上是一个函数,把 += 作用在左边的c2
{
complex c1(2 ,1);
complex c2(5);
c2 += c1;
}
那么既然是函数,我也可以自己定义
inline complex&
_doapl(complex* ths,const complex& r)
{
ths -> re += r.re;
ths -> im += r.im;
return *ths;
}
incline complex&
complex :: operator += (const complex& r)
{
return __doapl(this, r);
}
在上面重载中,隐含了一个this,也就是操作符作用的那个c2 ,完整来说上面应该是
complex :: operator += (this ,const complex& r)//不能写this,但是确实存在
+= 是把右边加到左边,右边就是r ,左边就是this,然后一步一步返回引用。完成 +=操作
任何一个成员函数有一个隐藏的this,一个指针,指向调用者,谁调用,就指向谁
1.8.2 非成员函数重载 2 无this
没有this pointer,函数作为全局函数,如果有多种情况,则需要多情况列出使用。
比如
complex c1(2 ,1);
complex c2;
c2 = c1 + c2;
对应的:
inline complex
operator + (const complex& x,const complex& y)
{
return complex(real(x) + real(y) , imag(x) + imag(y));
}
c2 = c1 + 5;
对应的:
inline complex
operator + (const complex& x,double y)
{
return complex(real(x) + y , imag(x));
}
以上均为return by value,而且不可以return by reference 。与 c2 += c1不同,是把c1加到c2上,返回引用,这里是吧c2 + c1,没有返回给c2 或者c1任何一个,也就是说,这个结果需要在函数里重新定义一个值,把结果给上去,但是,这是个local value ,离开函数就死亡,所以不能返回引用。
那么问题又来了,说好的在函数里创建一个值,接收结果,那值呢?这里使用的临时对象;
1.8.3临时对象 typename()
complex(real(x) + real(y) , imag(x) + imag(y))
complex是类名,创建一个临时对象,把结果给上去,这种赋值类似于 int(5)
complex();
complex(4,5);
//都是临时对象,下一行就不见了
再来看一个例子
inline complex
{
operator - (const complex& x)
{
return complex(real(x),-imag(x));
}
}
这里,需要把负值返回,所以又是一个临时变量
1.8.4 << 操作符重载
如何输出复数?
{
complex c1(2, 1);
cout << conj(c1);
}
<< 操作符,把右边的传到左边 也就是把conj(c1) / **共轭复数 * / 传给 cout,这种操作符只能写成全局的非成员函数。操作符两个参数第一个是cout,第二是是conj(c1)
#include <iostream.h>
ostream&
operator << (ostream& os , const complex& x)
{
return os << '(' << real(x)<<','<<imag(x)<<')';
}
(1)os部分可不可以写 const 不可以,表面上os没有更改,实际return中
把每个值都给了os
(2)单看cout<<conj(c1).输出后并不在乎返回值,所以此时返回void没错
(3)但是 cout<<c1<<conj(c1);就不行,右边的值返回,传给c1,c1再返回给cout
所以最后返回类型ostream&
总结
如何写好一个类?
(1)构造函数中 complex(double r=0, double i=0) : re (r), im(i) {}
会用
(2)考虑函数该不该加 const
(3)函数参数和返回值 考虑 by reference
(4)数据尽可能在private ,函数绝大部分在public