c++ & 对象用法,new用法 ,多态,virtual 虚函数用法(完全解析)

& 引用用法 在C++中 除了有继承关系的class 中多态用法,外还有两个类中 引用的效果:

测试代码如下

/*
* c++ 基本知识回顾
* 
* new 的使用方法
* ***********************************
* new 三个动作 :获得一块内存空间、调用构造函数、返回正确的指针
* virtual 虚函数的使用方法
* socket send buff 为object时 
* 以 new A() 这样方式的功能如下:
* 	- 在堆上分配空间
* 	- 在分配的空间上调用对象的构造函数
* 	(这也是 new 和 malloc的主要区别,是否调用构造函数)
* 
* 同理: 在调用 delete obj的时候:
* 	1. 首先调用 这个对象 的析构函数
* 	2. 然后释放这个对象的空间
* 
* new创建类对象需要指针接收,一处初始化,多处使用
* new创建类对象使用完需delete销毁
* new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
* new对象指针用途广泛,比如作为函数返回值、函数参数等
* 频繁调用场合并不适合new,就像new申请和释放内存一样
* 如果程序退出而没有执行delete则会造成内存泄漏
* //调用new:
* 
* 	A* pa = new A(3);
* 	那么上述动态创建一个对象的过程大致相当于以下三句话(只是大致上):
* 	A* pa = (A*)malloc(sizeof(A));
* 	pa->A::A(3);
* 	return pa;
* 
***********************************
* & :: 使用方法
* 一个类调用 两一个类的方法 可以用引用的方式
* 事先再 要调用的类(B)里面实例 要被调用的类(A)
***********************************
* virtual 函数用法注意
* 编译器在编译的时候,发现基类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表(即vtable),
* 该表是一个一维数组,在这个数组中存放每个虚函数的地址。
* c++ 多态性 包括两点 一个是 类的多态 和函数的多态 类的多态可以通过 虚函数 来实现 ,函数的多态可以 用重载
* C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。
* 如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
***********************************
* virtual 应用 场景**
* 当我们一个指针指向了子类,或者引用子类那么我们希望调用函数的时候是调用子类的函数,
* 但是实际情况却不是这样。这时候就需要virtual关键字了
* 纯虚函数: 含有 它的类叫抽象类 ,不能被实例化 即new()
* 
*/
#include <iostream>
#include <vector>
#include <map>
#include <fstream>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define SAFE_DETETE(p)	if(p) { delete(p); p = NULL; }

#define TEST_ST_NEW 0
#define TEST_ST_RE 0
#define TEST_ST_VIRTL 0
#define TEST_ST_VIRTL_INHER 1

typedef struct car
{
	string name;
	int num;
	char *typ;
} CAR,*P_CAR;

class A
{
	public:
		A(){ };
		int g_a_count ;
		string sa = "ls yq";
		void act();
		static int s_cs;
		~A(){ };
	
	private:

};

class B // HM
{
	public:
		A abb; //for 为了B 能引用
		B(){};
	
		~B(){ };
	
	private:
	
};

int A::s_cs = 3; // 类外定义成员 默认是 public

#if TEST_ST_VIRTL || TEST_ST_VIRTL_INHER 
class VA
{
	public:
		virtual void fuc(){cout<<" VA virtual fuc "<<endl;}
		int m_vacount;
		VA(){cout<<" VA() "<<endl;}
		virtual ~VA(){ cout << " ~VA() call "<< endl;}
		virtual void pure_v() = 0; // 子类必须实现 它
	
	protected:
		int m_prot;
	
	private:
		int prv;
	
	//基类的析构函数 声明为 虚函数 防止 内存泄露
	/* 原因: 原因是基类指针指向了派生类对象,而基类中的析构函数却是非virtual的,之前讲过,
	 * 虚函数是动态绑定的基础。现在析构函数不是virtual的,因此不会发生动态绑定,而是静态绑定,指针的静态类型为基类指针,
	 * 因此在delete时候只会调用基类的析构函数,而不会调用派生类的析构函数
	 */
	
};

class VB
{
	public:
	
		VB(){ };
		void VB_fun(){cout << " VB_fun() call "<< endl; }
		virtual void fuc(){cout<<"VB fuc "<<endl;}
	
		virtual ~VB(){ cout << " ~VB() call "<< endl;}
	
		private:
		protected:
	
};

class VC :public virtual VA
{
	public:
		VC(){ };
		
		virtual ~VC(){ cout << " ~VC() call "<< endl;}
		
	private:
	protected:
	

};

class VE :public virtual VA
{
	public:
		void fuc(){cout<<" VE fuc  "<<endl;}
};

class VF :public VE,public VC
{
	public:
		VF(){}
		~VF(){}
		void fuc(int c){cout<<" VF c = "<<c<<endl;}
		void pure_v(){cout<<" VF prue virtual fuc pure_v  "<<endl;}
};

#if TEST_ST_VIRTL
class VD :public VA
{
	public:
		VD(){cout << " VD()  "<< endl; };
		void fuc(){cout<<" VD fuc "<<endl;}	
		~VD(){ cout << " ~VD() call "<< endl;}
		void pure_v(){ cout<< " VD pure_v()" <<endl;}
		
		
	private:
	protected:
	

}vd_t;
#endif
/*
 *在多继承下,虚继承就是为了解决菱形继承中,
 *B,C都继承了A,D继承了B,C,那么D关于 A的引用只有一次,
 *而不是 普通继承的 对于A引用了两次
 */


#endif


int main(int argc,char *argv[])
{
#if TEST_ST_NEW	
	CAR *ca_t;
	ca_t->num =99;
	cout << "ca_t = "<<ca_t->num<<endl;

	car *ca = new car();// =  car *ca = new car
	ca->name = "BAOMA";
	ca->num = 66;
	ca->typ = "QICHE";
	cout << "ca->name = "<<ca->name<<endl;
	
	A* a = new A;// = A* a = new A();
	B* b = new B(); //在堆上
	
	cout << "a->g_a_count"<<a->g_a_count<<endl;
	
	A aa; //在栈上
	int buf[sizeof(A)];  //在栈上,分配一个数组
	A *ar = new(buf) A(); //在这个数组上构造一个 对象 A
	cout << "sizeof(A) = "<< sizeof(A)<<endl;
	SAFE_DETETE(a);
	SAFE_DETETE(b);
#endif

#if TEST_ST_RE
	B* bb;
	A &abb = bb->abb; // 用引用的方法 来调用 A 的 g_a_count
	abb.g_a_count =1999;
	cout << "abb.g_a_count = "<<abb.g_a_count<<endl;
	A  aaa;
	cout<<"aaa.g_a_count"<<aaa.g_a_count<< " A::s_cs = "<<aaa.s_cs<<endl;
	
	
#endif

#if TEST_ST_VIRTL
/***** 一个经典的例子 *****/
	VA *va = new VD(); // 基类 析构函数 定义成 virtual 可以 同时 析构基类和派生类的
	VD *vd = new VD(); // 可以同时 析构基类和派生类

	SAFE_DETETE(va); //同时  析构基类和派生类的
	SAFE_DETETE(vd);
cout<< "<<<<<< base class virtual delete >>>>>>" <<endl;
/***** virtual 多态用法 *****/
	VA *vaa = new VD(); // 不加 virtual invoke VA fuc, 加上 invoke VD fuc 
	VA *vdd; //VA *vdd = new VA() error: 定义了纯虚函数 那么 不能被实例化 !!!
	vdd= &vd_t;
/* [VD *vdd = new VD()] 和 [VA *vdd = new VD()]  同时 invoke  VA()+VD() */

	vdd -> fuc();// VD fuc 子类的 函数
	vdd -> pure_v(); // 次处注意 如果类中定义了纯虚函数 那么 不能被实例化 
	SAFE_DETETE(vaa);
cout<< "<<<<<< virtual base  for Derived fuc use >>>>>>" <<endl;	
#endif
/***** virtual inheritance  *****/
#if TEST_ST_VIRTL_INHER

cout<< "<<<<<< virtual inheritance >>>>>>" <<endl;
#endif

	VA *vf = new VF(); //如果 用 虚继承 只产生 一个 VA,如果 VC VE 不用 虚继承则 会产生两个 VA 的副本
	vf ->fuc(); 
	return 0;

}

代码测试方法:

可以 对应打开代码中的宏控来测试:

1为打开, 0为关闭

#define TEST_ST_NEW 0
#define TEST_ST_RE 0
#define TEST_ST_VIRTL 0
#define TEST_ST_VIRTL_INHER 1

发布了47 篇原创文章 · 获赞 44 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/yang_quan_yang/article/details/89284918