//guard 防卫式声明,在cpp中不需要按顺序include,避免重复include
#ifndef __COMPLEX__
#define __COMPLEX__
...
#endif
//class template
//inline function macro
template<typename T>
class complex
{
public:
complex(double r=0,double i=0):re(r),im(i){}//initial list
complex():re(0),im(0){}//overloading重载,但是上一行已经有默认参数,所以不可以有无参的重载
//return by reference
complex& operator +=(const comlpex&);
//const member functions,不改变成员变量
//定义时,const complex c(1,2)会出错
double real() const {return re;}
double imag() const {return im;} //函数在class body内定义,自动转换为inline函数
//不带指针的函数多半不用析构 string equal to *char[]
//相同class的各个对象互为友元
int func(const complex& param)
{return param.re + param.im;}
private:
T re, im;
//构造函数放在private区和单例模式有关
//友元函数可以自由访问我的private成员
friend comlpex& __doapl (complex*, const complex&);
};
//how to use template
complex<double > c1(2.5, 3.5);
complex<int > c2(1, 2);
//参数传递:按值传递(pass by value)、引用传递(pass by reference to const)
//按值传递,整包传过去,东西太大,不适合
//reference(指针),给地址、速度快,尽量传引用,如果传过去怕被改就加const
//返回值传递也尽量按引用返回
//& * 返回value,接收是&?
//传递者无需知道接受者是以reference形式接收
inline complex& __doapl(complex* ths, const complex& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
//操作符重载-1,成员函数
inline complex& complex::operator += (const complex& r)
{
//谁调用了这个函数,谁就是这个this,他在参数列表里,但是不能写出来
return __doapl(this, r);
}
//操作符重载-2,非成员函数,与上述不同在于下面的么有this
//并且他们只能按值返回return by value,因为是局部对象,函数作用域结束后对象就消失,空引用
//complex + complex
inline complex operator + (const complex& x, const complex& y)
{
return complex(real(x)+real(y),
imag(x)+imag(y));
}
//double+complex and complex+double
inline complex operator + (const complex& x,double y)
{
return complex(real(x)+y,imag(x));
}
inline complex operator+(const complex& x){return x;}//参数只有一个,正号
//negate取反,产生新结果,创建新对象
inline complex operator-(const complex& x)
{
//local object
//类名():临时对象
return complex(-real(x), -imag(x));
}
//关于<<,cout可能并不认识后面的东西,并不能像int、char这些基本类型去输出
//写成成员函数,被作用的对象就变成了类,导致cout变右边:c1.re()<<cout;不好
//这也是这里写成全局函数而非成员函数的原因
//共轭复数
//重载操作符必须写成全局的原因?????
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)<<')';
}
/*
cout<<conj(c1);
cout<<c1<<conj(c1);
*/
总结:
1.数据放在private。
2.参数尽可能的按引用传递。(传过去不想被改就加const)
3.返回值同上。
4.初始化列表。
有些重载操作符必须写成全局的原因?????
因为在全局中才能传参,完成复数+实数的一些操作,否则写在类中只能完成复数+复数。
class with pointer member
#ifndef __MYSTRING__
#define __MYSTRING__
...
#endif
//class带指针,一定要有拷贝构造、拷贝赋值
//若没有写,就会按位(bit)复制,不好。bit copy
//
class String
{
public:
String(const char* cstr = 0);
//拷贝构造
String(const String& str);
//拷贝赋值
String& operator = (const String& str);
//析构
~String();
char* get_c_str() const {return m_data;}
private:
//string = char*,动长,在不确定大小的情况下
char* m_data;//只有4个字节,指针的大小就是一个地址的长度
}
//default ctor,string is a pointer,passed into a pointer
inline String::String(const char* cstr = 0){
if(sctr){
//this 2 line is copy ctor,passed into must be a object,param &
m_data=new char[strlen(csrt)+1];
strcpy(m_data,cstr);
}else{
m_data=new char[1];
*m_data='\n';
}
}
//有动态分配的内存,要[]删除掉
inline String::~String(){
delete[] m_data;
}
int main(){
String s1();
String s2("hello");
String s3(s1);
cout<<s3<<endl;
s3=s2;
cout<<s3<<endl;
//
String* p = new String("hello");
delete p;
}
为什么有指针成员的类一定要有拷贝构造、拷贝赋值?
/*关于拷贝构造*/
String a("hello");
String b("world");
b=a;//这是浅拷贝
//a、b指向相同内容,原本b指向那块变成孤儿,导致memory leak
//修改a,b也会改变,当a析构后,b指向内容空,再去访问b的内容时,出错
//避免这种浅拷贝带来的不利,以下拷贝构造属于深拷贝
inline String::String(const String& str){
m_data=new char[strlen(str.m_data) + 1];//兄弟之间互为友元
strcpy(m_data, str.m_data);
}
{
String s1("hello");
String s2(s1);//以s1为蓝本创造一个新的给s2
//String s2=s1;
}
/*关于拷贝赋值*/
//虽然返回的是this指针,当进行连续赋值的时候,不能把返回类型设为空
inline String& String::operator=(const String& str){
//一定要检测自我赋值,否则一旦发生自我赋值时,程序会报错
if(this == &str)
return *this;
//被赋值一方先清空自己
delete[] m_data;
//创建一个和对象一样大的空间
m_data = new char[strlen(str.m_data)+1];
//把对象复制进来
strcpy(m_data,str.m_data);
return *this;
}
{
s2 = s1;//s1赋值给s2,this指向s2,
}
ostream& operator<<(ostream& os, const String& str){
os<< str.get_c_str();
return os;
}
{
cout<<s1;
}
Stack,存在于某作用域的一块内存空间。例如调用函数时,函数本身会形成一个栈用来保存他接收的参数,以及返回的地址。在函数体内声明的任何变量,使用的内存块都来自栈。
Heap,由操作系统提供的一块全局内存空间,程序动态分配从中获得若干区域。
/*堆、栈与内存管理*/
class Complex{...};
...
//全局对象,直到程序结束
Complex c3(1,2)
int main()
{
//c1占用的空间来自栈,auto object = local object会被自动清理
Complex c1(1,2);
//Complex(3)属于临时对象,其占用空间从堆中new得,并由p指向
Complex* p = new Complex(3);//new了就要delete
//static object在作用域结束后依然存在,直到整个程序结束
static Complex c2(1,2);
delete p;//没有的话会造成内存泄漏,本来有块内存,在某处失去了对这块内存的控制,无法delete还给操作系统,有限的内存。一旦离开这个作用域,这个指针就死亡了,但是它指向的内存空间没有释放,这就是内存泄漏。
}
news:先分配内存,在调用构造函数
Complex* p = new Complex(1,2);
==
//内部调用malloc(n)
void *mem=operator new(sizeof(Complex))//分配内存
pc = static_cast<Complex*> (mem);//转型
//Complex::Complex(pc, 1, 2);this指针指向pc
pc->Complex::Complex(1,2);//调用构造函数
delete:先调用析构,在释放内存
delete p;
==
String::~String(p);
//内部调用free(p)
operator delete(p);
//array new要搭配array delete,避免String[3]中只有第一块空间的动态分配内存被清空,而后面两块没有
//inline可以多写,效果依赖于编译器的决定
about static
//nice singleton
class A{
public:
static A& getInstance();
setup() {...}
private:
A();
A(const A& rhs);
...
};
A& A::getInstance(){
//need than create
static A a;
return a;
}
function template
stone r1(2,3),r2(3,3),r3;
r3 = min(r1,r2);//编译器会对函数模板做argument deduction
template <class T>
inline const T& min(const T& a, const T& b){
return b<a?b:a;
}
class stone{
public:
stone(int w,int h,int we):_w(w),_h(h),_weight(we){}
bool operator < (const stone& rhs) const{
return _weight<rhs._weight;
}
private:
int _w,_h,_weight;
}