天天看点

侯捷:C++面向对象高级编程

一、Object Based(基于对象) 不带指针(一般用不到析构函数)

头文件中的防卫式声名:

#ifndef __COMPLEX__ //如果没有定义过COMPLEX,则定义
#define __COMPLEX__
...
...
#endif
           

一、类模板

如类中private定义变量可以先不指定类型

template<typename T> 
class complex{
public:
//函数若在类内定义,则成为inline函数
    complex(double r=0,double i=0) : re(r),im(i)
    {}
    complex& operator += {const complex&);
    double real() const{
          return re;
          }
    double img() const{
          return im;
          }
 private:
    T re,im; //定义的变量设为私有
   
 friend complex& __doapl(complex*, const complex&);
};

complex<double> c1(6,1); //使用模板
           

二、构造函数:

1、函数名与类名相同

2、创建对象时使用,无返回值;

3、可以有默认实参;

//高级写法
complex(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(); //创建对象时不知道调用哪个构造函数
           

四、常量成员函数

double real() const{ //加const不会改变数据
          return re;
          }
    double img() const{
          return im;
          }
//如果没有定义const,创建const对象时不能调用函数
           

五、参数传递、返回值传递

引用传递(to const): (const complex&)传引用不希望被改值

传递者无需知道接收者是否以引用形式&接受

inline complex&
__doapl(complex* ths, const complex& r)
{
   ...
   return *ths;
}
           

六、友元函数

private:
    T re,im; //定义的变量设为私有
   
 friend complex& __doapl(complex*, const complex&);

__doapl(complex* ths, const complex& r)
{
  ths->re += r.re;
  ths->im += r.im; //直接取数据,不需要通过函数
  
  return *ths;
}
           

相同class中的各个对象互为友元

七、操作符重载

①成员函数

complex::operator += (这里隐藏着this但不能写出来, const complex& r)
{
      return __doapl(this,r); //this不可以在参数列写出来,但可以在使用时写出来
           

②非成员函数

inline complex(complex这个地方为返回类型)
operator + (const complex& x, const complex& y)
{
    return complex(real(x)+real(y), img(x)+img(y));
}
不能以引用返回,因为两个复数相加,会创建一个地方来存储值,函数结束后它会消失,以引用传递出去,接收者查看时本体已没有

conj (const complex& x)
{
    return complex(real(x), - img(x));
}

#include <iostream.h>
ostream& //返回类型 即cout的类型
operator << (ostream& os, const complex& x)
{
  return os << '(' << real(x) << ',' << img(x) << ')';
}

cout<<conj(c1);
cout<<c1<<cong(c1);
           

例:复数实现

//头文件
#ifndef __COMPLEX
#define __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 img() 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;
}

inline complex&
complex::operator += (const complex& r)
{
    return __doapl(this,r);
}

inline complex
operator + (const complex& x, const complex& y)
{
   return complex(real(x)+real(y), img(x)+img(y));
   //创建临时对象的时候赋值,返回
}
inline complex
operator + (const complex& x, double y)
{
   return complex(real(x)+y, img(x));
}

inline complex
operator + (double x, const complex& y)
{
   return complex(real(y)+x, img(y));
}
}

#endif
           
测试程序
#include <iostream.h>
ostream&
operator << (ostream& os, const complex& x)
{
  return os << '(' << real(x) << ',' << img(x) << ')';
           

二、Object Oriented(面向对象)带指针

字符串

测试程序:

#include "string.h"
#include <iostream>

using namespace std;

int main()
{
  String s1("hello"); 
  String s2("world");
    
  String s3(s2);  //拷贝构造
  cout << s3 << endl;
  
  s3 = s1;//拷贝赋值
  cout << s3 << endl;     
  cout << s2 << endl;  
  cout << s1 << endl;      
}
           

类定义

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:
   char* m_data; //指向字符串的指针
};
           

一、构造函数、析构函数

构造函数

String::String(const char* cstr = 0)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   //未指定初值
      m_data = new char[1]; //动态分配
      *m_data = '\0';
   }
}
           

析构函数

inline
String::~String()
{
   delete[] m_data; //动态分配后需要释放内存,不然会造成内存泄漏
}
           

二、浅拷贝:

String a(“Hello”);

String b(“World”);

b=a;

a里存放指向"Hello"的指针,b里存放指向"World"的指针,执行b=a后,会让b指针指向Hello,那么b原先指向的内容会没有指针指向,造成内存泄露,同时a,b指向同一内容,后续a修改内容也会对b造成影响;

三、深拷贝

拷贝构造函数:

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}
           

拷贝赋值函数:

先将左边的清空 ,再创建和右边一样的内存空间,然后将右边的数据拷贝到左边空间

自我赋值,当两个指针指向同一个内容,没有检测自我赋值,执行delete操作后,下一步操作时,str.m_data没有内容

inline
String& String::operator=(const String& str)
{
   if (this == &str) //检测自我赋值 如s2 = s1,那么this为s2,str为s1
      return *this;

   delete[] m_data; //先清空自己
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}
           

例:字符串实现

头文件

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:
     char* m_data; //4个字节
};

inline
String::String(const char* cstr = 0)
{
      if(cstr)
      {
          m_data = new char[strlen(cstr)+1];
          strcpy(m_data,cstr);
      }
      else
      {
          m_data = new char[1];
          *m_data='\0';
      }
}

inline
String::~String()
{
   delete[] m_data;
 }

inline
String::String(const String& str)
{
      m_data = new char[strlen(str.data)+1];
      strcpy(m_data,str.data);
}

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;
}
           

四、stack(栈)和heap(堆)

1、栈:存在于作用域的一块内存空间,当调用函数时,函数本身会形成一个stack来放置它接收的参数

2、堆:操作系统提供一块global内存空间,动态取得new,可以在程序任何地方动态获得,需要delete释放

static Complex c2(1,2);

其生命在作用域结束时仍然存在,直到程序结束

Complex* p = new Complex;

delete p;

3、new:先分配内存,在调用构造函数

Complex* pc = new Complex(1,2);

过程为:

Complex* pc;

① void* men = operator new(sizeof(Complex)); //分配内存

② pc = static_cast<Complex*>(men); //转型

③ pc->Complex::Complex(1,2); //构造函数

4、delete: 先调用析构函数,再释放内存

① String::~String(ps);

operator delete(ps); //相当于free()

array new要搭配array delete

不然只调用一次析构函数会造成内存泄漏

三、static

class Account{
public:
    static double m_rate;
    static void set_rate(const double& x)
    {
       m_rate = x;
    };
    double Account::m_rate = 8.0; //静态成员数据需要在类外定义
int main()
{
   Account::set_rate(5.0);
   Account a;
   a.set_rate(7.0);
}
           

补充:

using std::cout;

cout<< …;

四、复合 Composition 表示has-a

Container---->component

侯捷:C++面向对象高级编程

构造函数:Container的构造函数首先调用Component的默认构造函数,然后再执行自己

析构函数:Container的析构函数首先执行自己,再调用Component的析构函数

五、委托Delegation 用指针指向

Composition by reference

六、Inheritance(继承) 表示is-a

子类(派生类Derived)、父类(基类Base)

构造函数:子类的构造函数首先调用父类的默认构造函数,然后再执行自己

析构函数:子类的析构函数首先执行自己,再调用父类的析构函数

父类的析构函数要加virtual

① 虚函数:成员函数前加virtual //可能有默认定义

函数调用继承的是调用权

纯虚函数:virtual void draw() const = 0; //没有定义

继承和复合关系下的构造和析构

Ⅰ、

侯捷:C++面向对象高级编程

构造函数:由内到外

析构函数:由外到内

c++

继续阅读