C++——三种继承方式



一、单继承方式

先看代码:

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A()
	{ 
		cout << "A::A()    ";
	}
	
	~A()
	{ 
		cout << "A::~A()" << endl;
	}
};
class B :public A{
public:
	B()
	{ 
		cout << "B::B()    " << endl;
	}
	
	~B()
	{ 
		cout << "B::~B()    ";
	}
};
void func()
{
	cout << "constructor:  ";
	B b;
	cout << "destructor:   ";
}

void main()
{
	func();
	system("pause");
}
输出:


单继承方式:

        特性:继承了基类所有属性与行为,包括私有成员,但不允许派生类直接访问基类私有成员。


构造函数:

        派生类构造函数名(形参表):基类构造函数名(形参表){…}

要点:

        创建派生类对象时,程序首先创建基类对象,即基类对象应在进入派生类构造函数前被创建完成

        派生类构造函数应通过成员初始化表将基类信息传递给基类构造函数

        派生类构造函数应初始化派生类新增的数据成员

析构函数:

        派生类对象过期时,程序将首先调用派生类析构函数,然后调用基类的

虚析构函数:

        作用:和虚函数一样类似,在用基类指针释放派生类对象时候,为了能调用正确的析构函数。

        注意:当一个类有虚函数功能,它经常作为一个基类使用,并且它的派生类经常使用new来分配,那么它最好也使用虚析构函数,因为这样才能保证在释放实例对象的时候调用正确的析构函数


无虚析构函数:

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A(){ cout << "A::A()    "; }
	~A(){ cout << "A::~A()" << endl; }
};

class B :public A{
public:
	B(){ cout << "B::B()    " << endl; }
	~B(){ cout << "B::~B()    "; }
};
void func()
{
	B* pb = new B();
	delete pb;
}

void main()
{
	func();
	system("pause");
}
输出:


#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A(){ cout << "A::A()    "; }
	~A(){ cout << "A::~A()" << endl; }
};

class B :public A{
public:
	B(){ cout << "B::B()    " << endl; }
	~B(){ cout << "B::~B()    "; }
};
void func()
{
	A* pb = new B();
	delete pb;
}

void main()
{
	func();
	system("pause");
}
输出:


有虚析构函数:

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A()
	{ 
		cout << "A::A()    "; 
	}
	
	virtual ~A()
	{ 
		cout << "A::~A()" << endl; 
	}
};

class B :public A{
public:
	B()
	{ 
		cout << "B::B()    " << endl; 
	}
	
	~B()
	{ 
		cout << "B::~B()    ";
	}
};

void func()
{
	A* pb = new B();
	delete pb;
}
void main()
{
	func();
	system("pause");
}
输出:


#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A()
	{ 
		cout << "A::A()    "; 
	}
	
	virtual ~A()
	{ 
		cout << "A::~A()" << endl; 
	}
};

class B :public A{
public:
	B()
	{ 
		cout << "B::B()    " << endl; 
	}
	
	~B()
	{ 
		cout << "B::~B()    ";
	}
};

void func()
{
	B* pb = new B();
	delete pb;
}
void main()
{
	func();
	system("pause");
}
输出:


基类构造函数的调用:

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
	A()
	{ 
		cout << "this is A::A()" << endl;
	}
	A(int b)
	{ 
		cout << "this is A::A(int b):    the value of b is: " << b << endl; 
	}
	A(double b)
	{ 
		cout << "this is A::A(double b)    the value of b is: " << b << endl; 
	}	
};

class B :public A{
public:
	B():A(){}             //调用基类 A 默认构造函数
	B(int b): A(b){}      //调用基类 A 的 A::A(int b) 构造函数
	B(double b): A(b){}   //调用基类 A 的 A::A(double b) 构造函数
};

void main()
{
	B b0, b1(5), b2(10.5); //产生三个实例,分别调用不同的基类构造函数
	system("pause");
}
输出:



二、多继承方式

class 派生类名:继承方式 1 classname,继承方式2  classname2 … {….};

构造函数:

        派生类名:: 派生类名(形参表):基类名(形参表),基类名(形参表)…{…}

特点:
        同一层的基类构造函数的执行顺序取决于定义派生类对各基类的排列顺序,与定义派生类的构造函数时基类的排列顺序无关。

二定义性的原因:

  • 由于多层次的交叉派生类关系,造成一个派生类对象包含了基类成员的多个副体
  • 多个基类中某个成员名相同

方法:

        用虚基类来解决由于多层次的交叉派生类关系,用基类中定义成员的访问修改方法来解决多个基类中某个成员名相同


虚基类:

        采用虚基类定义方式定义派生类,在创建派生类时,类层次结构中某个虚基类的成员只保留一个,即虚基类成员的一个副本被所有派生类共享

        class 派生类名:virtual 继承方式 基类名,… { … };

注意:

  1. virtual与继承方式之间的次序无关且将基类作为虚基类,计算机为此完成一些额外计算量慎用;
  2. 一个类可以在一个类族中用作虚基类,也可以用作非虚基类;
  3. 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的对象;
  4. 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的;
  5. 最派生类是指在继承结构中建立对象时所指定的类;
  6. 在派生类的构造函数的成员初始化列表中,必须列出对虚基类构造函数的调用,如果没有列出,则表示使用该虚基类的缺省构造函数;
  7. 在虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中,都要列出对虚基类构造函数的调用.但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次;
  8. 在一个成员初始化列表中,同时出现对虚基类和非虚基类构造函数的调用时,基类的构造函数先于非虚基类的构造函数执行。

有虚基类和无虚基类的区别:


        由上图所示,有无虚基类的情况主要为:

  • 虚基类:D通过不同的方式继承A,仅有一个A对象;
  • 非虚基类:D通过不同的方式继承A,有多个A对象。

代码如下:

#include <iostream>
#include <string>
using namespace std;

class A{
protected:
	int a;
public:
	A()
	{
		this->a = 0;
	};
};

class B :public A{
public:
	void B_change(int b)
	{
		cout << "class B" << endl;
		cout << "the original of a is:   " << a << endl;
		a = b;
		cout << "the after change a is:   " << a << endl << endl;
	}
};

class C :public A{
public:
	void C_change(int c)
	{
		cout << "class C" << endl;
		cout << "the original of a is:   " << a << endl;
		a = c;
		cout << "the after change a is:   " << a << endl << endl;
		}
};

class D :public B, public C{ };

void main()
{
	D d;
	d.B_change(20);
	d.C_change(50);
	d.B_change(200);
	d.C_change(500);
	
	system("pause");
}
输出:


有虚基类继承:

代码:

#include <iostream>
#include <string>
using namespace std;

class A{
protected:
	int a;
public:
	A()
	{
		this->a = 0;
	};
};

class B :virtual public A{
public:
	void B_change(int b)
	{
		cout << "class B" << endl;
		cout << "the original of a is:   " << a << endl;
		a = b;
		cout << "the after change a is:   " << a << endl << endl;
	}
};

class C :virtual public A{
public:
	void C_change(int c)
	{
		cout << "class C" << endl;
		cout << "the original of a is:   " << a << endl;
		a = c;
		cout << "the after change a is:   " << a << endl << endl;
		}
};

class D :public B, public C{ };

void main()
{
	D d;
	d.B_change(20);
	d.C_change(50);
	d.B_change(200);
	d.C_change(500);
	
	system("pause");
}
输出:






版权声明:本文为xuyuqingfeng953原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。