C++继承

1 篇文章 0 订阅


前言

        在自然界中普遍存在着继承,很多东西都存在继承性。

        继承机制是面向对象程序设计使代码可以重复利用的重要手段,它允许在保持原有状态的情 况进行拓展,增加功能。

一、派生类的定义

        一个B类继承于A类,或者称类A派生类B,所以,类A称为基类(父类),那么类B就称为子类(派生类)。

那么派生类中的成员包括两部分:

        1.从父类继承过来的成员

        2.拓展的成员

        从父类继承过来的体现了其共性,而新增的成员体现其个性。

  其定义为

        class 派生类名 :继承方式 父类名{

        //派生类新增的数据和成员函数

        }

class Person{
	public://父类的成员函数
		void set(int age,string name){
			_age=age;
			_name=name;}
		void Print(){
			cout<<"age: "<<_age<<endl;
			cout<<"name:"<<_name<<endl; }
	protected:
		int _age;
		string _name;
};
class Student:public Person{//继承,Student继承person,且继承方式为public
	public://派生类自己拓展的成员函数
		Student(int stdID){
			_stdID=stdID;}
	protected://派生类自己拓展的属性
		int _stdID;
};

        继承相当于将父类中的代码复制到子类中。来验证一下

class Teacher:public Person{

};
	cout<<"Person大小:"<<sizeof(Person)<<endl; 
	cout<<"Teacher大小:"<<sizeof(Teacher)<<endl; 
	cout<<"Student大小:"<<sizeof(Student)<<endl; 

 可以大胆的猜测一下,类Teacher,类Student和类Person的大小。

Person大小:16
Teacher大小:16
Student大小:24

         类Teacher和类Person果然是相同的,而Student和Person不相同的原因是类Student中加入新的属性,而值得注意的是,加入的int型数据比Person类多8个字节,但是int类型应该占4个字节,这是因为字节对齐。前面也说过,函数放在代码区,数据放在栈上

二、访问控制符

三种继承方式(访问控制符):

        public:共有继承

        private:私有继承

        protected:保护继承

class A{
	public:
		int x;
		void set(){y=100;z=100;}
	protected:
		int y;
	private:
	 	int z;//在父类里面能访问,在父类外不能访问
		      // 在子类类里类外都不能访问 
};

 创建一个父类A,这里着重说一下protected和private在类里的区别

protected修饰的在子类里面可以访问

private修饰的在子类里不可访问

class B:public A{
	void set(){
		x=100;
		y=100;//protected修饰的可以访问
		//z=100;//[Error] 'int A::z' is private
		//用private来修饰,子类不能访问 
	}
};

二.继承关系

public 继承 保持父类访问控制符关系不变

protected 继承 父类的public在子类中表现为protected

private 继承 父类中的public和protected在子类表现为privata

class A{
	public:
		int x;
		void set(){y=100;z=100;}
	protected:
		int y;
	private:
	 	int z;
};

 public继承:

class B:public A{
	void set(){
		x=100;y=100;
		//z=100;//[Error] 'int A::z' is private
		//用private来修饰,子类不能类里类外都不能访问 
	}
};

 protected:

class C:protected A{//用protected 来继承的话将类里public属性改成protected 

};

         用protected继承后,在类里只能是protected和private作用域,无论是protected还是private在类外都不能访问。所以protected继承后,类外均不可以访问

 private:

class D:private A{用private来继承的话将类里public属性改成private

};

         用private方式继承后,在类只能是private,private域不能在外访问。同样的protected相同的,private继承后在类外是不能访问的。

        那么,protected和private有什么区别呢

        如果我们在对protected继承的C进行派生

class C:protected A{//用protected 来继承的话将类里public属性改成protected 
//    继承后的作用域
//	protected:
//		x;
//	protected:
//		y;
//	private:
//		z; 
};
 class E:public C{
//再继承后的作用域
//	protected:
//		x;
//	protected:
//		y;
	void set(){//对x,y进行赋值操作
		x=100;
		y=100;
	} 
};

对其进行再次继承后类E里面x,y只能在类里访问。

但是如果对private继承后的类进行再次继承

class D:private A{
//	private:
//		x;
//	private:
//		y;
//	private:
//		z; 
};
 class F:public D{
//	private:
//		x;
//	private:
//		y;
//	void set(){
//		x=100;[Error] 'int A::x' is inaccessible
//		y=100;在之前的继承继承中,D中所有属性被修改成了private 
//	} 
};

 这个时候如果再对x,y进行赋值,报错。

所以继承关系用public,protected和private就看后面的几次继承。

三.析构函数和构造函数

         构造时:先对基类进行构造,然后对子类进行构造

        析构时:先对子类进行析构,再对父类进行析构

#include<iostream>
using namespace std;
class A{
	public:
		A(){cout<<"A()"<<endl;}
		~A(){cout<<"~A()"<<endl;}
};
class B:public A{
	public:
		B(){cout<<"B()"<<endl;}
		~B(){cout<<"~B()"<<endl;}
};
int main(){
	B b;
	return 0;
} 
A()
B()
~B()
~A()

二.构造函数的巧用

初始化一个对象的时候不免要对其属性进行赋值,

 对父类中的public属性,赋值的方法比较多,在类外就可以赋值。

父类中protected属性,无法在类外进行赋值,可以在类里进行赋值

父类中private属性,只有在父类里面进行赋值 

当然,都可以在父类里写个set函数,通过在子类里面调用,如上面的

void set2(int z){ z=z;}

 void set(){ x=100;y=100;set2(100); }

当然,简单的成员属性这样初始化,但是当属性多了这样写效率会很低的

用下面这个方法可以提高效率

        在调用子类构造函数时使用 初始化成员列表

            A(int x,int y,int z):x(x),y(y),z(z){
                 }

           B(int a,int b,int c):A(a,b,c){
            }

class A{
	public:
		int x;//对于x而言,有三种方法进行初始化 
//		void set2(int z){
//			z=z;
//		}
	A(){
		cout<<"A()"<<endl;
	}
	A(int x,int y,int z):x(x),y(y),z(z){
//		x=x;y=y;z=z;
	cout<<"A(int x,int y,int z)"<<endl;
	}
	protected:
		int y;//对y来说,有两种 
	private:
		int z;//对于z而言有两种 
};
class B:public A{
//	void set(){
//		x=100;
//		y=100;
//		set2(100);
//	}
	public:
		B(){
			cout<<"B()"<<endl;
		}
		B(int a,int b,int c):A(a,b,c){
			cout<<"B(int a,int b,int c)"<<endl;
		}
};

四.父类与子类成员名冲突

如果我们在构造子类和父类的时候,如果不小心将子类和父类中成员函数和成员变量的名设置相同了,那么会不会继承下去,或者说继承后又该怎么样去使用?

class A{
	public:
		int a;
		void func(){cout<<"A::void func(int a)"<<endl;}
};
class B:public A{
	public:
		int a;
		void func(){cout<<"B::void func(int a)"<<endl;}
};

当在子类B中去使用成员变量a,使用的是子类B中的变量a,同样的道理调用func函数时候一样调用的是子类的中的函数,那么B类有没有继承A类呢,肯定继承了,不过被隐藏了,我们可以用sizeof来求出类B的大小来判断。

	cout<<sizeof(B)<<endl;//输出  8

那么该怎么使用到父类中的成员呢?

作用域::

子类对象.父类名::父类成员

    B b;
    b.A::a=200;
    cout<<b.A::a<<endl;//200

 用这样的方法就可以调用到子类中隐藏的父类成员。

五.多继承和菱形继承

多继承:

class 子类名:继承方式 父类1 , 继承方式 父类2,

class A{
	public:
		int a; 
};
class B{
	public:
		int b;
};
class C:public A,public B{
	public:
		int c;
};

 菱形继承:

 像这样的继承方式称为菱形继承

class A{
	public:
		int a; 
};
class B:public A{
	public:
		int b;
};
class C:public A{
	public:
		int c;
};
class D:public B,public C{
	public:
		int d;
};

 菱形继承有个缺点:当在使用D类对象对a属性进行操作是,编译器不知道该属性是来自B还是来自C

	D d;
	cout<<sizeof(d)<<endl;	//40
    d.a=100;//[Error] request for member 'a' is ambiguous

 虚继承

引入虚继承来解决这个问题:在继承方式前加上  virtual

class A{
	public:
		int a; 
};
class B:virtual public A{
	public:
		int b;
};
class C:virtual public A{
	public:
		int c;
};
class D:public B,public C{
	public:
		int d;
};

虚继承的类将共享他们父类的数据

静态成员

静态变量的特点:

1.能继承到子类对象中去

2.当子类中从写父类中的静态变量时,父类中的静态变量被隐藏

3.访问父类中被隐藏的成员时用::

class A{
	public:
		static int a;//静态成员的定义 ,放在数据区 
		static int func(){return a;}//静态成员函数只能访问静态成员变量 ,放在代码区 		
};
int A::a=100; //静态成员的初始化 
class B:public A{

}; 
	A a;
	cout<<a.func()<<endl;//100
	B d;
	cout<<d.func()<<endl;//100
	b.a=110;//判断共享
	cout<<a.func()<<endl;//110
	cout<<d.func()<<endl;//110
	//静态成员变量是共享的
	cout<<sizeof(d)<<endl;//1

父类和子类的静态成员变量之间是共享的,当然共享的不仅仅是变量还有成员函数。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值