一、头文件与类的声明
1.guard(防卫式声明)
在complex.h文件中写出:
#ifndef __COMPLEX__
#define __COMPLEX__
…
#endif
2.header的布局
0--forward declarations(前置声明)
1--class declarations(类声明)
2--class definition(类定义)
3.class declaration
class head
class body
二、构造函数
1.class template
template
class classname
{
public:
......
private:
T data1,data2;
};
2.inline 函数
(1)内联的目的:
1. C中使用define这种形式宏定义的原因是因为,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。
2. 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。
3. 在C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。
4. inline 推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了宏定义的缺点,同时又很好地继承了宏定义的优点。
(2)内联原理:
直接执行替换而不进行一般函数的参数压栈,在预处理阶段即可完成。
1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。
2. 很明显,类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
3. inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。
(3)内联的用法:
函数若在class body内定义完成,便自动成为inline候选。在外部定义的成员函数需要显式的添加上inline。外部全局函数也是直接在前面加上inline。
内联函数最重要的使用地方是用于类的存取函数。
(4)内联成功的条件:
1.没有分支(循环、开关)没有函数调用;
2.没有取函数指针的操作;
3.函数形式简单。
3.访问级别
4.构造函数
目的:创建对象是完成初始化。
用法:
1.构造函数的命名必须和类名完全相同;
2.没有返回值,也不能用void来修饰;
3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用;
4.构造函数有回滚的效果,构造函数抛出异常时,构造的是一个不完整对象,会回滚,将此不完整对象的成员释放;
5.如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认构造函数:a.如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;b.如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);c.在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。
5.构造函数可以有很多个(操作符重载-1,overloading)
事实上重载会以函数名加参数名组合一起命名。
三、参数传递与返回值
1.单例模式(singleton)
1.私有构造函数不能通过new关键字来创建其对象,一个应用是单例模式(singleton);
2.单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
2.const member functions(常量成员函数)
返回类型 成员函数 const { ... };//function内部不允许改变本类的数据
3.参数传递
(pass by value or pass by reference (Is or not to const?))
一般,基本类型用pass by value;复杂类型用pass by reference。尽可能保证参数传递较少的值;
4.返回值传递
(return by value or return by reference(Is or not to const?))
1.尽可能保证返回值传递较少的值;
2.不可返回local变量的引用。牢记作用域!
5.友元函数
1.可以自由取得friend的private成员。
2.相同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; }
private:
double re, im;
};
{
complex c1(2, 1);
complex c2;
c2.func(c1);
}
这里c2可以直接取得c1的私有变量。
6.classbody外的各种定义
注意不能传递局部变量的引用
doassignment plus
inline complex & __doapl (complex * ths, const comples & r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
inline complex & complex::operator += (const complex&r)
{
return __dopal (this, r);
}
四.操作符重载
1.operator overloading(操作符重载-1,成员函数)有this
inline complex & __doapl (complex * ths, const comples & r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
inline complex & complex::operator += (const complex& r)
{
return __dopal (this, r);
}
inline complex & complex::operator += (this, const complex& r)//this不能写出来
{
return __dopal (this, r);
}
{
complexc1(2, 1);
complexc2(5);
c2 += c1;//操作到c2
}
2.returnby reference语言分析
传递着无需知道接收者是以reference形式接收
inlinecomplex & __doapl (complex * ths, const comples & r)
{
...
return*ths;
}
inlinecomplex & complex::operator += (const complex& r)
{
return __dopal (this, r);
}
这是相对于用指针的一大优势
3.operatoroverloading(操作符重载-2,非成员函数)无this
inline complex operator + (const complex& x, const complex& y)
{
return complex (real(x) + real(y), imag(x) + imag(y));
}
inline complex operator + (const complex& x, double y)
{
return comple(real(x) + y, imag(x));
}
inline complex operartor + (double x, const complex& y)
{
return complex(x + real(y), imag(y));
}
4.临时对象typename();
//这里一定不能return by reference
inline complex operator + (const complex& x, const complex& y)
{
return complex (real(x) + real(y), imag(x) + imag(y));//这个返回是一个local object
}
{
int(7);
complex c1(2, 1);
complex c2;
complex();
comple(4, 5);//这两个临时对象到下面就没了
cout << complex(2);
}
5.一元运算符的重载
inline complex operator + (const comple& x)
{
return x;
}
inline complex operator - (const complex& x)
{
return complex(-real(x), -imag(x));
}
{
complex c1(2, 1);
complex c2;
cout << -c1;
cout << +c1;
}
其它:
两个复数的等于,不等于,共轭复数,模运算,极坐标到笛卡尔坐标的转换
inline complex conj (const complex&x)
{
return complex (real(x), -imag(x));
}
ostream& operator << (ostream& os, const complex& x)
{
return os << '(' << real(x) << ',' << imag(x) << ')';
}
设计一个类小结:
1.成员函数尽量放到public,数据尽量放到private
2.函数参数传递尽量考虑pass by reference;加不加const要考虑
3.返回值尽量以return by reference,除非需要返回临时对象
4.成员函数如果不改变数据值的,函数body大括号前要加const
5.尽量使用initializationlist初始化构造函数和成员函数的值
1.构造一个类的步骤:
a.防卫式声明别忘记;
b.这个类有哪些数据,什么类型的?写进private区;
c.构造函数怎么写?参数是否要有默认值?参数是否有必要returnby reference?没有返回类型。写进public区。
d.是否要有取得私有数据值的函数的成员函数,写进public区。返回类型和参数return by reference?不改变成员变量所有要在类成员函数加const?
e.是否需要重载一些操作符?写成全局函数形式还是成员函数形式?(全局形式可以完成更加泛型一些的操作,如果确定该重载操作符只与该对象本身有关,就携程成员函数)
f.是否需要友元以便直接访问私有数据?
2.类名后面加小括号可以创建临时对象,可以用于返回值。
3.当该对象与其他类型使用此重载操作符的的时候,需要全局函数重载。
4.尽量要写<<的重载。
�
网友评论