继承-----新

继承是面向对象复用的重要手段,通过继承定义一个类继承是类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。

在前面我们学到类和对象的时候有三种访问限定符,1.public(公有)2.protected(保护)3.private(私有),当时学的时候我们知道,在类外protected和private不能被访问,可是那为什么,还要定义一个protected呢?告诉你吧,他们在继承中体现了不一样。

一   在继承中有三种继承方式:

二   三种继承关系下基类成员在派生类的访问关系变化图:

总结:1.基类的私有成员在派生类是不可见的(不能被访问),如果一些基类成员不想被基类对象直接访问,但需要在派生类中访问,就定义为保护成员。可以看出保护成员限定符是因为继承才出现的。

2.public继承是一个接口继承,保持is_a原则,每个父类可用的成员对子类也可用,每个子类是一个父类,因此每个子类对象也都是一个父类对象(前提是父类没有定义私有成员)

3.protected/privated继承是一个实现继承 ,是has-a原则,父类的东西有可能在类外不可用,或不能访问,一个基类对象有一个派生类对象,父类和子类访问权限不一。

4.不管哪种继承方式,在派生类中都可以访问基类的公有和保护成员,但是基类的私有成员在子类都存在,不可见即不能访问

5.使用关键字class的默认继承方式是private,使用关键字struct 默认的继承方式是public

思考:保护继承,A父类成员在B子类全部变成保护的(除父类私有成员),则在类外都不能访问

          私有继承,A父类成员在B子类全部都变成私有的(除父类私有),则在类外也都不能访问

          那这两种继承有什么区别呢?区别在于下一个继承子类C中,保护继承B中的成员可见,而私有继承中B中

          成员全部变为不可见。

三  通过继承父类的所有成员变为子类的一部分(包括成员变量,成员函数)算对象大小时不算成员函数,因为成          员函数编译是一段指令,放代码段,所有对象共享.

#include<iostream>
using namespace std;
class A
{

public:
	int _a;
public:
	void FA()
	{
		cout << "void FA()" << endl;
	}
};
class B :public A
{
public:
	void FB()
     {
		   cout << "void FB()" << endl;
     }

public:
	int _b;
};
int main()
{
	B b;
	A a;
	a._a = 1;
	b._a = 2;//说明成员变量可以被继承
	b._b = 3;
	b.FA();//说明成员函数也可以被继承

	return 0;
}

  赋值兼容规则

     1.子类对象可以赋值给父类对象(切片)

     2.父类对象不能赋值给子类对象

     3.父类的指针/引用可以指向子类对象(切片)

     4.子类的指针和引用不能指向父类对象(可以通过强制类型转换完成)

#include<iostream>
using namespace std;
class A
{

public:
	int _a;
public:
	void FA()
	{
		cout << "void FA()" << endl;
	}
};
class B :public A
{
public:
	void FB()
     {
		   cout << "void FB()" << endl;
     }

public:
	int _b;
};
int main()
{
	B b;
	A a;
	a._a = 1;
	b._a = 2;//说明成员变量可以被继承
	a = b; //(切片)
	//b = a;//不可以
	A* p1 = &b;//切片  虽然指向b,但是只访问A类型那么大的空间
	A& r1 = b;//
	//B* p2 = &a;编译不通过
	//B& r2 = a;编译不通过
	B* p2 = (B*)&a; //可以编译通过
	 B& r2 =(B&) a;//可以编译通过
	 cout << p2->_b << endl;//越界读不出错
	 p2->_b = 10;//越界写出错
	return 0;
}

  继承体系中的作用域

1.在继承体系中基类和派生类都有自己独立的作用域

2.子类和父类中有同名成员,子类对象访问将隐藏子类从父类继承下来的同名成员(包括成员指针,成员函数)

面试爱考

#include<iostream>
using namespace std;
class A
{

public:
	int _a;
public:
	void FA()
	{
		cout << "void FA()" << endl;
	}
};
class B :public A
{
public:
	void FB()
     {
		   cout << "void FB()" << endl;
     }

public:
	int _b;
};
int main()
{
	B b;
	A a;
	b._a = 1;//访问子类的,隐藏
	return 0;
}

面试爱考:

#include<iostream>
using namespace std;
class A
{

public:
	int _a;
public:
	void F(int a)
	{
		cout << "void FA()" << endl;
	}
};
class B :public A
{
public:
	void F(char* a)
     {
		   cout << "void FB()" << endl;
     }

public:
	int _b;
};
int main()
{
	B b;
	b.F(10);//子类F(char*a)隐藏父类F(int a),但是又传的是10,与char* 不匹配,因此报错
	
	return 0;
}

      六    派生类的默认成员函数

       在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统会默认合成这六个默认的成员函数

     

重点:

#include<iostream>
using namespace std;
class Person
{
public:
	Person(const char*name = "nihao ")
		:_name(name)
	{
		cout << "Person(const char*name)" << endl;
	}
	Person(const Person& p)
		:_name(p._name)
	{
		cout << "Person(const Person& p)" << endl;

	}
	Person& operator=(const Person& p)
	{
		cout << "Person& operator=(const Person& p)" << endl;

		if (this != &p)
		{
			_name = p._name;
		}
		return *this;
	}
	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name;

};
class Student :public Person
{
public:
	Student(const char*name = "haha", int d = 2)
		:_d(d)
		, Person(name)// _name(name)错误      子类只初始化自己的成员,显示调用父类的构造函数来初始化父类的
	{
		cout << "Student(const char*name, int d)" << endl;
	}
	Student(const Student&s)
		:_d(s._d)
		, Person(s)//切片子类对象赋给父类引用    子类只初始化自己的成员,显示调用父类的构造函数来初始化父类的
	{
		cout << "Student(const Student&s)" << endl;
	}
	Student& operator=(const Student&s)
	{
		cout << "Student& operator=(const Student&s)" << endl;
		if (this != &s)
		{
			this->Person::operator=(s);//必须指定父类的operator=,不然出现栈溢出,因为子类隐藏了父类的同名函数
			_d = s._d;
		}
		return *this;
	}
	~Student()
	{
		cout << " ~Student() " << endl;//子类析构完成时,会自动调用父类析构
	}
protected:
	int _d;
};
int main()
{
	Student s("daidai", 12);
	Student s2(s);
	Student s3("hehe", 4);
	s3 = s;
	system("pause");
	return 0;
}


七  单继承&多继承

菱形继承:存在:二义性 -------》指定作用域可以解决

                           数据冗余------》虚继承可以解决

菱形继承对象模型:

代码如下:

#include<iostream>
using namespace std;
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;
};
int main()
{
	D d;
	cout << sizeof(d) << endl;//20
	d._a = 1;//菱形继承存在二义性
	d.B::_a = 1;//指定作用域解决了二义性
	d.C::_a = 2;//指定作用域解决了二义性
	d._c = 3;
	d._b = 4;
	d._d = 5;
	system("pause");
	return 0;

}

菱形虚拟继承对象模型


#include<iostream>
using namespace std;
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;
};
int main()
{
	D d;
	cout << sizeof(d) << endl;//24
	d.B::_a = 1;
	d.C::_a = 2;
	d._c = 3;
	d._b = 4;
	d._d = 5;
	system("pause");
	return 0;

}

看下面一个题,面试爱考


  友元关系不能继承,也就是说基类友元,不能访问子类私有和保护成员

#include <iostream>
using namespace std;
class B;
class A
{
public:friend void Display(A& a, B& b);
	   A(int a = 1)
		   :_a(a)
	   {}
private:int _a;

};
class B :public A
{
public:B(int b = 1)
	   :_b(b)
{}

protected:

	int _b;
};
void Display(A& a, B& b)
{
	cout << a._a << endl;
	cout << b._b << endl;//友元不能被继承
}
int main()
{
	A a(2);
	B b(3);
	Display(a, b);
	system("pause");
	return 0;
}



  继承与静态成员(可以继承)

基类定义了static成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例

#include <iostream>
using namespace std;
class Person
{
public: Person()
	{
		++ _count;
	}
public:
	static int _count;
};
int Person::_count = 0;
class Student :public Person
{
protected:int _stunum;
};
class Graduate :public Student
{
protected:int _id;
};
int main()
{
	Person s1;
	Student s2;
	Graduate s3;
	cout << "人数" << Person::_count << endl;
	Student::_count = 0;
	cout << "人数" << Person::_count << endl;
	system("pause");
	return 0;
}



 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值