C++学习笔记:(六)public、protected、private继承详解

前言

上一篇学习了继承的基础概念以及示例代码。算是对继承有了一个简单的了解。如果想要对继承有更深的了解,就要复习访问权限的知识点。这样才能深化对继承的了解,以及学习不同的继承方式能对哪些数据进行操作。

类成员包括数据成员和函数成员,分别描述问题的属性和行为,是不可分割的两个方面。对类成员访问权限的控制,是通过设置成员的访问控制属性来实现的。访问控制属性有:公有类型、私有类型和保护类型。这里简单的说一下不同类型的作用。公有类型成员定义了类的接口。私有成员只能被本类的成员函数和友元函数访问,来自类外部的任何访问都是非法的。这样,私有成员就完全隐藏在类中,保护了数据的安全性。保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对派生类影响不同。

类中public、protected和private数据成员、函数成员的使用:

#include <iostream>
using namespace std;

class Asd
{
	public:
		int x;
		Asd(int a = 0, int b = 0, int c = 0);
		int getx(){return x;}
		int gety(){return y;}
                void sety1(int b){y = b;}
		int getz(){return z;}
                void setz1(int c){z = c;}
		void sety2(int b){protectedsety(b);}
		void setz2(int c){privatesetz(c);}
		void print()
		{
			cout << "X:" << x << " " << "Y:" << y << " " << "Z:" << z <<endl;
		}
	protected:
		int y;
		void protectedsety(int b){y = b;}
	private:
		void privatesetz(int c){z = c;}
		int z;
};

Asd::Asd(int a, int b, int c)
{
	x = a;
	y = b;
	z = c;
}

int main()
{
	Asd a(3, 2, 3);
        a.print();                  //通过print()函数打印
        a.sety1(3);                 //通过public中的函数设置y
        a.setz1(4);                 //通过public中的函数设置z
        a.print();
        a.sety2(4);                 //由protected中的函数设置y
        a.setz2(5);                 //由private中的函数设置z
        cout << "(x,y,z):";
        cout << "(" << a.getx() << "," << a.gety() << "," << a.getz() << ")" <<endl;  //由public中的函数得到数据
        cout << "X:" << a.x <<endl;   //正确,对象可以直接访问公有数据
        //cout << "Y:" << a.y <<endl; //错误,对象不能直接访问保护数据
        //cout << "Z:" << a.z <<endl; //错误,对象不能直接访问私有数据
        //a.protectedsety(1);         //错误,对象不能直接访问保护成员函数
        //a.privateserz(1);           //错误,对象不能直接访问私有成员函数
	return 0;
}

在这个示例代码中,每种类型都有数据成员和函数成员。可以清楚的看到public中的函数是如何充当接口的。在这个类中,可以通过public中的函数直接设置y、z的值,也可以通过public中的函数去访问protected和private中的函数,最终达到设置y、z值的目的。在public中的数据成员可以通过”对象名.数据成员”的方式直接使用,而其他类型的数据成员则不行。

 

接下来开始分析不同的继承方式:

公有继承:

#include <iostream>
using namespace std;

class Point
{
	private:
		float x;
		float y;
                float findx()const{return x;}
	protected:
                void setz(int a){z = a;}
		float z;
	public:
		void initPoint(float x = 0, float y = 0, float z = 0)
		{
			this->x = x;
			this->y = y;
			this->z = z;
		}
		Point(){}
		Point(float r)
		{ 
			x = r;
		}
		void move(float a, float b)
		{
			x += a;
			y += b;
		}
		float getx()const{return x;}
		float gety()const{return y;}
                float getz()const{return z;}
		float getprivatex()const{return findx();}
};

class Rectangle:public Point
{
	private:
		float w,h;
	public:
		void initRectangle(float x, float y, float w, float h)
		{
			initPoint(x,y);
			this->w = w;
			this->h = h;
		}
		float geth()const{return h;}
		float getw()const{return w;}
                //float publicgetx1()const{return getx();}            //正确,getx()是基类公有成员函数
                //float publicgetx2()const{return findx();}           //错误,findx()是基类中的私有成员函数
                float publicgetx3()const{return getprivatex();}       //正确,getprivatex()是基类公有成员函数
                void publicsetz(int a){setz(a);}                      //正确
};

int main()
{
	Rectangle rect;
	rect.initRectangle(2,3,10,10);
        rect.move(3,2);
	cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
        cout << "X:" << rect.publicgetx3() <<endl;
        rect.publicsetz(20);
        cout << "Z:" << rect.getz() <<endl;
        //rect.setz(1);       //错误,派生类对象不能直接访问基类保护成员函数
        //rect.findx();       //错误,派生类对象不能直接访问基类私有成员函数
	return 0;
}

(1)基类的private、public、protected成员的访问属性在派生类中保持不变。

(2)派生类中继承的成员函数可以直接访问基类中所有成员派生类中新增的成员函数只能访问基类的public和protected成员,不能访问基类的private成员。

在上述代码中,基类中的move(),getx(),gety()都被派生类继承了,而且move(),getx()&gety()在基类中就是public中的函数。由(1)可知,派生类对象可以直接使用这些函数。由派生类中新增的三个publicgetx()函数可知,派生类新增函数能访问public成员,不能访问private成员。由publicsetz()可知,派生类新增函数能访问protected成员。若想让派生类中的新增成员函数访问private成员,可以通过基类中public中的函数间接的访问基类的private成员(如:publicgetx3()函数)。可以这样做,但一般不会这样做,因为在做项目的时候是不会动基类的。

(3)通过派生类的对象只能访问基类的public成员。(rect.setz(1)和rect.findx()报错的原因是它们不是基类public的成员函数)

 

保护继承:

#include <iostream>
using namespace std;

class Point
{
	private:
		float x;
		float y;
		float findx()const{return x;}
	protected:
		void setz(int a){z = a;}
		float z;
	public:
		void initPoint(float x = 0, float y = 0, float z = 0)
		{
			this->x = x;
			this->y = y;
			this->z = z;
		}
		Point(){}
		Point(float r)
		{ 
			x = r;
		}
		void move(float a, float b)
		{
			x += a;
			y += b;
		}
		float getx()const{return x;}
		float gety()const{return y;}
		float getz()const{return z;}
		float getprivatex()const{return findx();}
};

class Rectangle:protected Point
{
	private:
		float w,h;
	public:
		void initRectangle(float x, float y, float w, float h)
		{
			initPoint(x,y);
			//setz(10);               //派生类可以访问基类保护成员函数
			this->w = w;
			this->h = h;
		}
		void move(float a, float b){Point::move(a,b);}       //与public继承的不同
		float getx()const{return Point::getx();}             //与public继承的不同
		float gety()const{return Point::gety();}             //与public继承的不同
		float getz()const{return Point::getz();}             //与public继承的不同
		float geth()const{return h;}
		float getw()const{return w;}
		//float publicgetx1()const{return getx();}            //正确,getx()是基类公有成员函数
		//float publicgetx2()const{return findx();}           //错误,findx()是基类中的私有成员函数
		float publicgetx3()const{return getprivatex();}       //正确,getprivatex()是基类公有成员函数
		void publicsetz(int a){setz(a);}                      //正确
};


int main()
{
	Rectangle rect;
	rect.initRectangle(2,3,10,10);
	rect.move(3,2);
	cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
	cout << "X:" << rect.publicgetx3() <<endl;
	rect.publicsetz(20);
	cout << "Z:" << rect.getz() <<endl;
	//rect.setz(1);       //错误,派生类对象不能直接访问基类保护成员函数
	//rect.findx();       //错误,派生类对象不能直接访问基类私有成员函数
	return 0;
}

(1)基类的public、protected成员都以protected身份出现在派生类中。

(2)派生类中新增的成员函数可以直接访问基类中的public和protected成员,但不能访问基类的private成员。

由(1)可知,基类的public成员都以protected身份出现在派生类中,所以派生类的对象不能像公有继承那样直接使用基类中public的函数。而是要根据需求添加成员函数。例如:

void initRectangle(float x, float y, float w, float h)
{
    initPoint(x,y);
    this->w = w;
    this->h = h;
}
void move(float a, float b){Point::move(a,b);}       //与public继承的不同
float getx()const{return Point::getx();}             //与public继承的不同
float gety()const{return Point::gety();}             //与public继承的不同
float getz()const{return Point::getz();}             //与public继承的不同

因为派生类中新增的成员函数可以直接访问基类中的public和protected成员,而且在派生类中没有initPoint()的同名函数,所以在initRectangle()函数中可以直接使用initPoint()函数,而不需要写成Point::initPoint();。如果派生类对象要使用getx()函数,那么就要在派生类public中定义:

方法一:指明getx()的来历
float getx()const{return Point::getx();}。
方法二:为了避免重名可以写成:
float protectedgetx()const{return getx();}。

(3)通过派生类的对象不能访问基类的任何成员。(因为继承来的成员以protected身份出现在派生类中)

 

私有继承:

#include <iostream>
using namespace std;

class Point
{
	private:
		float x;
		float y;
		float findx()const{return x;}
	protected:
		void setz(int a){z = a;}
		float z;
	public:
		void initPoint(float x = 0, float y = 0, float z = 0)
		{
			this->x = x;
			this->y = y;
			this->z = z;
		}
		Point(){}
		Point(float r)
		{ 
			x = r;
		}
		void move(float a, float b)
		{
			x += a;
			y += b;
		}
		float getx()const{return x;}
		float gety()const{return y;}
		float getz()const{return z;}
		float getprivatex()const{return findx();}
};

class Rectangle:private Point
{
	private:
		float w,h;
	public:
		void initRectangle(float x, float y, float w, float h)
		{
			initPoint(x,y);
			this->w = w;
			this->h = h;
		}
		void move(float a, float b){Point::move(a,b);}       //与public继承的不同
		float getx()const{return Point::getx();}             //与public继承的不同
		float gety()const{return Point::gety();}             //与public继承的不同
		float getz()const{return Point::getz();}             //与public继承的不同
		float geth()const{return h;}
		float getw()const{return w;}
		//float publicgetx1()const{return getx();}            //正确,getx()是基类公有成员函数
		//float publicgetx2()const{return findx();}           //错误,findx()是基类中的私有成员函数
		float publicgetx3()const{return getprivatex();}       //正确,getprivatex()是基类公有成员函数
		void publicsetz(int a){setz(a);}
};

int main()
{
	Rectangle rect;
	rect.initRectangle(2,3,10,10);
	rect.move(3,2);
	cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
	cout << "X:" << rect.publicgetx3() <<endl;
	rect.publicsetz(20);
	cout << "Z:" << rect.getz() <<endl;
	//rect.setz(1);       //错误,派生类对象不能直接访问基类保护成员函数
	//rect.findx();       //错误,派生类对象不能直接访问基类私有成员函数
	return 0;
}

(1)基类的public、protected成员都以private身份出现在派生类中。(与保护继承的不同)

(2)派生类中新增的成员函数可以直接访问基类中的public和protected成员,但不能访问基类的private成员。(这里和保护继承的情况是一样的)

(3)通过派生类的对象不能访问基类的任何成员。(因为继承来的成员以private身份出现在派生类中)。可以和上述保护继承一样,通过新增成员函数让对象使用基类的一些操作。

数据成员和函数成员在继承过程中以相应继承方式出现在派生类中的情况可以这样理解:

注意:private和protected之间的区别只有在基类派生的类中才能表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对外而言,保护成员的行为与私有成员相似;对内而言,保护成员的行为与公有成员相似。

 

私有继承与保护继承的区别:

在上述的代码中,私有继承和保护继承的区别可能不是很明显。要想了解的更深,我们可以在Rectangle类的基础上再派生新的类,在新的派生类中看不同的继承方式对类中各成员的影响。

保护继承后再公有继承:

#include <iostream>
using namespace std;

class Point
{
	private:
		float x;
		float y;
		float findx()const{return x;}
	protected:
		void setz(int a){z = a;}
		float z;
	public:
		void initPoint(float x = 0, float y = 0, float z = 0)
		{
			this->x = x;
			this->y = y;
			this->z = z;
		}
		Point(){}
		Point(float r)
		{ 
			x = r;
		}
		void move(float a, float b)
		{
			x += a;
			y += b;
		}
		float getx()const{return x;}
		float gety()const{return y;}
		float getz()const{return z;}
		float getprivatex()const{return findx();}
};

class Rectangle:protected Point
{
	private:
		float w,h;
	public:
		void initRectangle(float x, float y, float w, float h)
		{
			initPoint(x,y);
			//setz(10);               //派生类可以访问保护成员函数
			this->w = w;
			this->h = h;
		}
		void move(float a, float b){Point::move(a,b);}       //与public继承的不同
		float getx()const{return Point::getx();}             //与public继承的不同
		float gety()const{return Point::gety();}             //与public继承的不同
		float getz()const{return Point::getz();}             //与public继承的不同
		float geth()const{return h;}
		float getw()const{return w;}
		//float publicgetx1()const{return getx();}            //正确,getx()是基类公有成员函数
		//float publicgetx2()const{return findx();}           //错误,findx()是基类中的私有成员函数
		float publicgetx3()const{return getprivatex();}       //正确,getprivatex()是基类公有成员函数
		void publicsetz(int a){setz(a);}
};

class A:public Rectangle
{
	private:
		float a;
	public:
		void initA(float x)
		{
			initRectangle(1,2,3,4);
			a = x;
                        setz(20);                                      //正确,setz()是Point类的protected成员              
		}
		//float getx()const{return Rectangle::getx();}         //正确  
                float getx()const{return Point::getx();}               //正确
};


int main()
{
	Rectangle rect;
	rect.initRectangle(2,3,10,10);
	rect.move(3,2);
	cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
	cout << "X:" << rect.publicgetx3() <<endl;
	rect.publicsetz(20);
	cout << "Z:" << rect.getz() <<endl;
	//rect.setz(1);       //错误,派生类对象不能直接访问基类保护成员函数
	//rect.findx();       //错误,派生类对象不能直接访问基类私有成员函数
	A a;
        a.initA(10);
	cout << "A.getx():" << a.getx() <<endl;
	return 0;
}

因为Rectangle类是保护继承,Point类的public、protected成员都以protected身份出现在派生类中,而A是公有继承的(基类各属性保持不变),所以在A类中新增成员函数可以使用setz()函数。而且在定义A类中getx()函数时,以下两种形式都是正确的。(改变class A的继承方式,上面的程序都能正常运行)原因是保护继承后再公有继承,A类仍然可以访问到Point类的成员。

float getx()const{return Rectangle::getx();}       
float getx()const{return Point::getx();}

私有继承后再公有继承:

#include <iostream>
using namespace std;

class Point
{
	private:
		float x;
		float y;
		float findx()const{return x;}
	protected:
		void setz(int a){z = a;}
		float z;
	public:
		void initPoint(float x = 0, float y = 0, float z = 0)
		{
			this->x = x;
			this->y = y;
			this->z = z;
		}
		Point(){}
		Point(float r)
		{ 
			x = r;
		}
		void move(float a, float b)
		{
			x += a;
			y += b;
		}
		float getx()const{return x;}
		float gety()const{return y;}
		float getz()const{return z;}
		float getprivatex()const{return findx();}
};

class Rectangle:private Point
{
	private:
		float w,h;
	public:
		void initRectangle(float x, float y, float w, float h)
		{
			initPoint(x,y);
			this->w = w;
			this->h = h;
		}
		void move(float a, float b){Point::move(a,b);}       //与public继承的不同
		float getx()const{return Point::getx();}             //与public继承的不同
		float gety()const{return Point::gety();}             //与public继承的不同
		float getz()const{return Point::getz();}             //与public继承的不同
		float geth()const{return h;}
		float getw()const{return w;}
		//float publicgetx1()const{return getx();}            //正确,getx()是基类公有成员函数
		//float publicgetx2()const{return findx();}           //错误,findx()是基类中的私有成员函数
		float publicgetx3()const{return getprivatex();}       //正确,getprivatex()是基类公有成员函数
		void publicsetz(int a){setz(a);}
};

class A:public Rectangle
{
	private:
		float a;
	public:
		void initA(float x)
		{
			initRectangle(1,2,3,4);
			a = x;
                        //setz(20);                                    //报错,因为setz()是Point的保护成员
		}
                float getx()const{return Rectangle::getx();}           //正确
                //float getx()const{return Point::getx();}             //错误,不能访问Point类的getx()
};

int main()
{
	Rectangle rect;
	rect.initRectangle(2,3,10,10);
	rect.move(3,2);
	cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
	cout << "X:" << rect.publicgetx3() <<endl;
	rect.publicsetz(20);
	cout << "Z:" << rect.getz() <<endl;
	//rect.setz(1);       //错误,派生类对象不能直接访问基类保护成员函数
	//rect.findx();       //错误,派生类对象不能直接访问基类私有成员函数
        A a;
        a.initA(10);
        cout << "A.getx():" << a.getx() <<endl;
	return 0;
}

上述代码可以这样理解:

结合上面两个代码和图片可以看出私有继承与保护继承的区别。①因为Rectangle私有继承后,基类的public、protected成员都以private身份出现在派生类中。而setz()函数是Point类中的保护成员(相当于第三种情况),在Rectangle中是私有成员,所以A类中不能访问setz()函数(A的新增成员函数只能访问私有继承的Rectangle中的A2,B2,但是setz()相当于是B1)。②Rectangle类中的getx()函数在public中,A类中的新增成员函数能访问到(Rectangle的getx()相当于是A2),所以float getx()const{return Rectangle::getx();}是正确的。由于Rectangle私有继承Point,所以A访问不到Point类的getx()函数(Point类的getx()相当于是A1),所以float getx()const{return Point::getx();}是错误的,换句话说就是私有继承后再公有继承的派生类访问不到上上个基类的成员。以上两点就是公有继承与私有继承的区别。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tyler_Zx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值