C++

● ::

::是作用域操作符,在使用命名空间是经常使用到::,该命名空间就是一个作用域。在定义类的成员函数时也经常用到::,表示类的作用域。

● C++版本的C标准库

C标准库的名字:name.h

对应的C++标准库为cname

cname文件中定义的名字在std空间中,而如果使用C标准库的头文件,名字不属于std

● 声明、定义

只声明不定义,使用extern关键字

extern int i; //只声明,未定义

int j; //声明,并定义

● 多态

多个不同类的对象对同一个方法的调用产生不同的结果。

多态有三种实现方式:函数重载、运算符重载、虚函数。

多态分编译时的多态和运行时的多态。

覆盖:基类中有个非虚函数,子类中也有个同名,同参的非虚函数。

重载:函数名相同,参数类型、个数不同

参考:

http://www.cnblogs.com/cxq0017/p/6074247.html

http://blog.csdn.net/jixianghahaxiao/article/details/45645035

● 数组指针

int (*p)[5]; 指向长度为5的数组的指针

int (*p)[5] = a[3][5]

p++,移动了一个一维数组

指针相减,返回的是实例的个数,而不是地址的差值

  char a[5]={'A','B','C','D'};
  char (*p3)[5] = &a; //正确

● new/delete

new/delete不是函数,是关键字;

下面几个是C++标准库函数

void *operator new(size_t); //allocate an object

void *operator delete(void *); //free an object

void *operator new[](size_t); //allocate an array

void *operator delete[](void *); //free an array

new申请内存的步骤:

1.调用operator new库函数申请空间,但未初始化

2.调用类的构造函数,对上一步申请的空间进行初始化(如果不是类类型,则不会初始化)

3. 返回对象的地址

delete步骤:

1. 调用类的析构函数(如若是类类型)

2. 调用operator delete函数,释放内存

new [] 会多分配4字节的内存来记录分配了多少个对象

delete []释放内存的时候,会调用operator delete[]函数

参考:http://blog.csdn.net/hazir/article/details/21413833

● static关键字

 static分为面向过程和面向对象两种用法。

面向过程:

static全局变量:存储在全局数据区;如果未初始化,则默认初始化为0;不可被其他文件的代码访问,即使他文件用extern关键字(但是通过include包含该源文件,则,可以通过编译);

static局部变量:存储在全局数据区;如果未初始化,则默认初始化为0;作用域为该函数;

static函数:不可被其他文件的代码访问;

面向对象:

static变量:属于类,所有对象共享;存储在全局数据区,不能再类里初始化;可以在其他函数里引用(前提是符合public、protected、private访问控制);两种访问方式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

 class load
{
public:
  load()
  {
    this->date = 2017;
  }
  static int sum;
  int get_interest();
  int get_date();
  static int get_sum_static();
  static int get_date_static();

private:
  int date;
  static int interest;
};

int load::interest = 1;
int load::sum = 10;

int load::get_interest()
{
  return interest;
}
int load::get_date()
{
  return this->date;
}
int load::get_sum_static()
{
  return load::sum; //OK
}
int load::get_date_static()
{
  return 0;
  //return this->date; //出错,static函数不存在this指针
}

int main()
{
   load ld;

  cout << load::sum << endl;
  cout << ld.sum << endl;
 
  //cout << load::interest << endl; //编译出错,
  //cout << ld.interest << endl; //编译出错,

  cout << ld.get_interest() << endl;
  cout << ld.get_date() << endl;

  cout << ld.get_sum_static() << endl;
  cout << ld.get_date_static() << endl;

  return 0;
}

static成员函数:属于类;可以访问其他static成员函数和static成员变量,但不可访问非static函数和变量(由于没有this指针);非static成员函数可以访问static成员函数和static成员变量;调用方式:<类名>::<静态成员函数名>,或<对象>.<静态成员函数名>,或<对象指针>-><静态成员函数名>

●  对象作为参数

参数传递对象的时候,会产生一个const类型的临时对象。如果函数的参数声明为非const,会报错,例如:

       string foo( );
       void bar(string&s)
       // 那么下面的表达式将是非法的:
       bar(foo( ));
       bar("hello world");

●   函数返回引用

1. 函数不可返回局部变量的引用,因为函数返回时,局部变量会消失,引用指向的变量为空。

       2. 尽量避免返回new申请的对象,因为这样很可能会引起内存泄漏,虽然这样做是合  法的。

       例如:

       string& foo()
       {
              string* str = new string("abc");
              return *str; 
       }

       string str = foo(); //内存泄漏,str得到的是一个副本,foo申请的内存无法释放(没有变 量指向它)。下面的做法可以解决这个问题(麻烦):

       string& tmp = foo();
       string str = tmp; 
       delete &tmp;

       但是下面的做法,不知不觉就造成了内存泄漏:

       string str = "hello" + foo(); 

●  拷贝构造函数

默认拷贝构造函数是,类中没有明确定义,编译器自动生成的拷贝构造函数。

class man

 {

     private:

         int age;

     public:

        man( int age )

         {

            this->age = age;

         }

         man( const man& m ) //拷贝构造函数

         {

             age = m.age;

         }

         void print()

         {

             cout << age << endl;

         }

 };

 拷贝构造函数的参数一定要定义为常引用,例如const man& m,否则会编译出错。

●  拷贝构造函数调用的时机

1. 以值传递的方式作为参数:func( man m);

2. 以值传递的方式从函数返回:func() { return m}

3. 赋值、初始化:man m2 = m

● 浅拷贝

浅拷贝是指对对象中的成员执行简单的复制。例如下面的rect2,它的p成员与renct的p指向同一个地址。这样,当执行对象销毁的时候,rect1和rect2都会对p进行析构,因此会发生错误。正确的做法是,两个对象的p成员的地址不同,但地址中的值相同。因此,需要深拷贝。

class Rect
{
public:
  Rect() // 构造函数,p指向堆中分配的一空间
  {
    p = new int(100);
  }
  ~Rect() // 析构函数,释放动态分配的空间
  {
    if(p != NULL)
    {
      delete p;
    }
  }
  private:
  int width;
  int height;
  int *p; // 一指针成员
};

int main()
{
  Rect rect1;
  Rect rect2(rect1); // 复制对象
  return 0;
}

● 深拷贝

对于动态成员,应该重新分配内存空间,因此需要定义拷贝构造函数:

class Rect
{
public:
Rect() // 构造函数,p指向堆中分配的一空间
{
  p = new int(100);
}
~Rect() // 析构函数,释放动态分配的空间:
{
  if(p != NULL)
  {
    delete p;
  }
}

Rect( const Rect & r) // 拷贝构造函数
{

  p = new int( *( r.p ) );
}
private:
int width;
int height;
int *p; // 一指针成员
};

● 防止调用默认拷贝函数

定义一个私有的拷贝函数,当用户试图值传递类对象是会报错:

private:     

  Rect (const Rect & R);  //拷贝构造,只是声明  

func ( rect1); //报错

拷贝构造函数,参考:http://blog.csdn.net/lwbeyond/article/details/6202256/

posted @ 2017-09-17 15:46  volcanorao  阅读(309)  评论(0)    收藏  举报