c++ 继承是否需要调用父类的构造函数

今天遇到一个继承的问题。请回答下面问题:(已知 B 继承自 A)

  • 子类是否需要调用父类的构造函数?必须还是可选?

先回答:

  • 结论1 :强烈建议显示调用父类构造。因为有些父类可能会初始化一些成员变量,子类又不知道他初始化了哪些变量。
  • 结论2:写父类的时候仅写一个构造函数。写一堆构造方法,别人写子类的时候调用哪个呢?

展示一些野生程序员的父类,让我写子类的时候一堆坑。

例子1: 父类有成员未定义,建议你显示调用父类构造。

别人的父类:
class A
{
public:
	A(int data = -1): value1(data) {}

	int value1; // 正确初始的成员变量
	char * value2;// 未初始化的成员变量,你一旦用了就报错
	int value3;// 未初始化的成员变量,但有默认值0。
};

这种情况下,如果你的子类不调用,就会报错,而且是你的过错。

你的子类
class B : A
{
public:
	不建议的构造
	B(int data) : name(data) {
		cout <<  *value2 << endl; // 报错,调用野指针
	}
		
	建议的构造
	B(int data) : A(data), name(data) {
		cout <<  *value2 << endl; // 也会报错,但责任不在你
	}	

	int name;
};

其实就是父类和子类各自管好各自的成员。

例子2 :父类的构造别定义一堆

有人喜欢这样定义父类:

 
class CRectangleData  
{
public:
	CRectangleData();
	CRectangleData(const double &dStartPosX, const double &dStartPosY, const double &dWidth, const double &dHeight);
 
private:
	double m_dStartPosX;	//起点横坐标
	double m_dStartPosY;	//起点纵坐标
	double m_dWidth;		//宽度
	double m_dHeight;		//高度
};

不好:

  • 你有默认构造,子类就可以不用显示调用父类构造。我写子类的时候,到底调用你哪个父类构造呢?
  • 哪些参数是必须的?哪些参数是可以设置的?哪些参数是默认的?没有体现出来。容易造成必须参数的未定义。

实际案例

项目:绘图程序
需求:绘制各种形状

  • 父类:shape
  • 子类:三角形、圆形等

先定义一些非必要的东西。

enum class ShapeType
{
	Shape_Unknown		= 0,	//未知形状
	Shape_Rectangle		= 1,	//矩形
	Shape_Ellipse		= 2,	//椭圆
	Shape_Triangle		= 3,	//三角形
};

不好的写法:

  • 不好的1:父类、子类成员变量没有“初始化”,都是在构造函数中赋值;
  • 不好的2:子类构造中应该体现:必须设置变量、可设置变量和不可设置变量三种
父类
class CShapeData
{
public:
	CShapeData()
	{
		m_ShapeType = ShapeType::Shape_Unknown; 
	}
protected:
	 ShapeType	m_ShapeType;//形状类型
};

子类椭圆形
class CEllipseData : public CShapeData
{
public:
 	CEllipseData() // 不建议:无意义的定义
 	{
 		m_ShapeType		= ShapeType::Shape_Ellipse;
		m_dStartPosX	= 0.0;
		m_dStartPosY	= 0.0;
		m_dRadiusW		= 0.0;
		m_dRadiusH		= 0.0;
 	}
	CEllipseData(const double &dStartPosX, const double &dStartPosY, const double &dRadiusW, const double &dRadiusH)
	{
		m_ShapeType		= ShapeType::Shape_Ellipse;
	
		m_dStartPosX	= dStartPosX;
		m_dStartPosY	= dStartPosY;
		m_dRadiusW		= dRadiusW;
		m_dRadiusH		= dRadiusH;
	}
	 
private:
	double m_dStartPosX;	//起点横坐标
	double m_dStartPosY;	//起点纵坐标
	double m_dRadiusW;		//横向半径长度
	double m_dRadiusH;		//纵向半径长度
};

修改如下:

父类
class CShapeData
{
public:
	CShapeData(ShapeType shape):m_ShapeType(shape)  // 修改地方1 : a) 使用初始化列表 b) 必须设定 m_ShapeType 值
	{}
protected:
	 ShapeType	m_ShapeType; 
};

子类椭圆形
class CEllipseData : public CShapeData
{
public:
  	// 修改地方2:a) 唯一的构造 b) 父类、子类各自初始化自己的变量
	CEllipseData(const double &dStartPosX, 
				 const double &dStartPosY, 
				 const double &dRadiusW, 
				 const double &dRadiusH) : CShapeData(ShapeType::Shape_Ellipse)m_dStartPosX	(dStartPosX),
				 						   m_dStartPosY	(dStartPosY),
				 						   m_dRadiusW   (dRadiusW),
				 						   m_dRadiusH   (dRadiusH)
	{}
	 
private:
	double m_dStartPosX;	//起点横坐标
	double m_dStartPosY;	//起点纵坐标
	double m_dRadiusW;		//横向半径长度
	double m_dRadiusH;		//纵向半径长度
};

你可能感兴趣的:(c++,开发语言)