查缺补漏

1.const

//file1.cpp
int a;
//file2.cpp
extern int a;
a++

//上述是正确的,但是下面就会出错
//file3.cpp
const int a;
//file4.cpp
extern int a;
a++

const会把变量变为局部变量,只允许本文件访问,如果想用const,又不想其为局部变量可以加一个extern修饰const,如:

//file1.cpp
extern const int a=1;//定义并初始化
//file2.cpp
extern const int a;
a++

2.定义一个引用的时候必须初始化如:

int a = 2;
int &p;//出错
int &o1 = a;//正确

3.const引用

const int i = 1;
const iny &p1 = i;//正确,两个都是const
int &p2 = i;//错误,非const引用指向const对象

同时,const引用可以指向右值,而非const引用只能指向其对应的对象。

const int &p = 4;//合法
const int  &p1 = p+3;//合法
int &p3 = 5;//非法

4.友元(转http://www.cppblog.com/twzheng/articles/21020.html)

采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。


友元函数:

友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:

      friend  类型 函数名(形式参数);

      友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
      一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
      友元函数的调用与一般函数的调用方式和原理一致。

友元类:

      友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。       
      当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
      friend class 类名;
      其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

      例如,以下语句说明类B是类A的友元类:
      class A
      {
             …
      public:
             friend class B;
             …
      };
      经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

      使用友元类时注意:
            (1) 
友元关系不能被继承。 
          (2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
          (3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

5.virtual的使用

#include <iostream>
using namespace std;
class A
{
	public:
		A()
		{
			cout << "构造函数A\n";
		}
		virtual void print()
		{
			cout << "我是A的print\n";
		}
		void nor()
		{
			cout << "我是A的nor\n";
		}
};
class B: public A
{
	public:
		B()
		{
			cout << "构造函数B\n";
		}
		void print()
		{
			cout << "我是B的print\n";
		}
		void nor()
		{
			cout << "我是B的nor\n";
		}
};
int main(int argc, char *argv[])
{
	A *p;
	A a;
	B b;
	p = &a;
	p->print();
	p->nor();
	p = &b;
	p->print();
	p->nor();
	return 0;
}
//注解:使用了virtual的函数声明时,当父类指针指向子类对象的时候,通过该指针调用
//该函数,若子类没有重写该函数,那么会调用父类的函数,若子类重写了,则会调用子类的
//函数,即通过virtual声明的函数,若子类重写了该函数,那么当通过指向子类的父类指针
//调用该函数时,会调用实际的对象内部的函数,即调用的是子类的函数,而如果没有使用
//virtual关键字声明函数,那么调用的都是父类的函数,而不是调用对象自己的函数 
输出结果是:


面向对象的多态性:引用和指针的静态类型与动态类型可以不同,这是 C++ 用以支持多态性的基石。 通过基类引用或指针调用基类中定义的函数时,我们并不知道执行函数的对象的确切类型,执行函数的对象可能是基类类型的,也可能是派生类型的。 如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数。如果调用虚函数,则直到运行时才能确定调用哪个函数,运行的虚函数是引用所绑定的或指针所指向的对象所属类型定义的版本。


6.操作符重载

   重载操作符必须具有一个类类型操作数,操作符的优先级、结合性或操作数目不能改变。重载操作符并不保证操作数的求值顺序,尤其是,不会保证内置逻辑 AND、
逻辑 OR和逗号操作符(第 5.9 节)的操作数求值。在 && 和 || 的重载版本中,两个操作数都要进行求值,而且对操作数的求值顺序不做规定。

  因此,重载 &&、|| 或逗号操作符不是一种好的做法。

  大多数重载操作符可以定义为普通非成员函数或类的成员函数。作为类成员的重载函数,其形参看起来比操作数数目少 1。作为成员函数的操作符有一个隐含的 this 形参,限定为第一个操作数。 


7.指向指针的引用

   int *&p = &a;//其中a是int类型变量;

   定义应该从右边看起,首先p是一个引用,然后p又是一个指针,所以p是一个指向引用的指针。

假设我们想编写一个与前面交换两个整数的 swap 类似的函数,实现两个指
针的交换。已知需用 * 定义指针,用 & 定义引用。现在,问题在于如何将这两
个操作符结合起来以获得指向指针的引用。这里给出一个例子: 
     // swap values of two pointers to int 
     void ptrswap(int *&v1, int *&v2) 
     { 
         int *tmp = v2; 
         v2 = v1; 
         v1 = tmp; 
     } 
形参 
     int *&v1 
 的定义应从右至左理解:v1 是一个引用,与指向 int 型对象的指针相关联。也就是说,v1 只是传递进 ptrswap 函数的任意指针的别名

8.指针和引用的区别

    1.指针在定义的时候可以不初始化,但是引用必须初始化;

    2.指针可以重新赋值,但是引用不能重新赋值;

    3.指针有自己的内存空间,但是引用没有,因此通过指针访问是间接访问,而通过引用则是直接访问。


9.指针常量和常量指针

    指针常量:const int *p 和 int const *p

    常量指针:int * const p


原文地址:https://www.cnblogs.com/arbboter/p/4225231.html