C++ 继承和多态

1. 继承

1.1继承的作用(重点)

1.代码复用,2.扩展类的功能

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//继承的作用1.代码复用。2.扩展类的功能
class Father
{
public:
	void func1()
	{
		cout << "约小姐姐" << endl;
	}
	void func2()
	{
		cout << "有钱" << endl;
	}
};

class Father01
{
public:
	void func1()
	{
		cout << "约小姐姐" << endl;
	}
	void func2()
	{
		cout << "有钱" << endl;
	}
};

class Son :public Father
{
public:
	void func3()
	{
		cout << "有才" << endl;
	}
};

class Son2 :public Father
{
public:
	void func3()
	{
		cout << "有才" << endl;
	}
};

void test()
{
	Son s;
	s.func1();
	s.func2();
	s.func3();
}
int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

1.2 继承方式(重点)

1.继承方式,公有继承,私有继承,保护继承
2.子类对从父类继承过来的成员的权限

1.公有继承

​ 1.父类的公有属性成员,到子类还是公有
​ 2.父类的私有属性成员,到子类不能访问
​ 3.父类的保护属性成员,到子类还是保护

2.保护继承

​ 1.父类的公有属性成员,到子类是保护
​ 2.父类的私有属性成员,到子类不能访问
​ 3.父类的保护属性成员,到子类还是保护

3.私有继承

​ 1.父类的公有属性成员,到子类还是私有
​ 2.父类的私有属性成员,到子类不能访问
​ 3.父类的保护属性成员,到子类还是私有

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;
private:
	int b;
protected:
	int c;
};

class Son1 :public Father
{
public:
	void func()
	{
		a;
		//b;err
		c;
	}
	/*
	公有继承:
	1.父类的公有属性成员,到子类还是公有
	2.父类的私有属性成员,到子类不能访问
	3.父类的保护属性成员,到子类还是保护
	*/
};
void test01()
{
	Son1 s1;
	s1.a;
	//s1.b;err
	//s1.c;err
}
//保护继承
class Son2 :protected Father
{
public:
	void func()
	{
		a;
		//b;err
		c;
		/*
		保护继承
		1.父类的公有属性成员,到子类是保护
		2.父类的私有属性成员,到子类不能访问
		3.父类的保护属性成员,到子类还是保护
		*/
	}
};

void test02()
{
	Son2 s2;
	//s2.a;err
	//s2.b;err
	//s2.c;
}

class Son3 :private Father
{
public:
	void func()
	{
		a;
		//b;err
		c;
		/*
		私有继承
		1.父类的公有属性成员,到子类是私有
		2.父类的私有属性成员,到子类不能访问
		3.父类的保护属性成员,到子类还是私有
		*/
	}
};
class Son33 :public Son3
{
public:
	void func()
	{
		//a;err
		//c;err
	}
};
void test03()
{
	Son3 s3;
	//s3.a;err
	//s3.b;err
	//s3.c;err
}
int main()
{

	system("pause");
	return EXIT_SUCCESS;
}


1.3 继承中的构造与析构(重点)

构造与析构的顺序

  • 子类对象在创建时会首先调用父类的构造函数
  • 父类构造函数执行完毕后,才会调用子类的构造函数
  • 当父类构造函数有参数时,需要在子类初始化列表(参数列表)中显示调用父类构造函数
  • 析构函数调用顺序和构造函数相反
    在这里插入图片描述
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Father
{
public:
	Father()
	{
		cout << "Father构造函数" << endl;
	}
	~Father()
	{
		cout << "Father析构函数" << endl;
	}
};

class Son :public Father
{
public:
	Son()
	{
		cout << "Son构造函数" << endl;
	}
	~Son()
	{
		cout << "Son析构函数" << endl;
	}
};
//先调用父类的构造函数,再调用本身的构造函数,析构函数调用顺序反之
void test01()
{
	Son s;
}

class A
{
public:
	A()
	{
		cout << "A 的构造" << endl;
	}
	~A()
	{
		cout << "A 的析构" << endl;
	}
public:
	Son s;
};

class B
{
public:
	B()
	{
		cout << "B 的构造" << endl;
	}
	~B()
	{
		cout << "B 的析构" << endl;
	}
};

class C
{
public:
	C()
	{
		cout << "C 的构造" << endl;
	}
	~C()
	{
		cout << "C 的析构" << endl;
	}
};

class D:public A
{
public:
	D()
	{
		cout << "D 的构造" << endl;
	}
	~D()
	{
		cout << "D 的析构" << endl;
	}
public:
	B b;
	C c;
};
void test02()
{
	D d;
}
int main()
{
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

1.4 继承中同名成员的处理方法(了解)

继承中同名函数的加载方法:

  • 当子类成员和父类成员同名时,子类依然从父类继承同名成员
  • 如果子类有成员和父类同名,子类访问其成员默认访问子类的成员(本作用域,就近原则)
  • 在子类通过作用域::进行同名成员区分(在派生类中使用基类的同名成员,显示使用类名限定符)
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		a = 10;
	}

	void func()
	{
		cout << "Father func" << endl;
	}
	void func(int a)
	{
		cout << "Father func(int a)" << endl;
	}

	void func(int a,int b)
	{
		cout << "Father func(int a,int b)" << endl;
	}


public:
	int a;
};
class Son :public Father
{
public:
	Son()
	{
		a = 20;
	}
	void func()
	{
		cout << "Son func" << endl;
	}
public:
	int a;
};
//当子类和父类有同名成员时,子类的同名成员会隐藏父类的同名成员
void test()
{
	Son s;
	cout << s.a << endl;
	cout << sizeof(Son) << endl;//8
	Father f;
	s.Father::a = 200;
	//通过父类名加作用域来访问
	cout<<s.Father::a << endl;
	
	cout << f.a << endl;


}
//当子类有和父类同名函数时,父类的所有函数重载都会被隐藏
void test02()
{
	Son s;
	s.func();
	//s.func(10);err
	//s.func(10, 20);err
	//通过作用域来访问隐藏的父类函数
	s.Father::func(10);
	s.Father::func(10, 20);
}
int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

1.5 继承中的静态成员特性(了解)

静态成员函数和非静态成员函数的共同点:
1.静态成员可以被继承
2.继承中的静态成员变量一样会被同名的子类成员变量隐藏
3.继承中的静态成员函数中,当子类有和父类同名静态函数时,父类的所有重载静态函数都会被隐藏
4.改变从基类继承过来的静态函数的某个特征,返回值或者参数个数,将会隐藏基类重载的函数
5.静态成员函数不能是虚函数
6.从父类继承过来的静态成员变量是父类的静态成员变量

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Father0
{
public:
	static int mA;
};
class Father :public Father0
{
public:
	static void func()
	{
		cout << "Father func()" << endl;
	}
	static void func(int a)
	{
		cout << "Father func(int a)" << endl;
	}

	static void func(int a, int b)
	{
		cout << "Father func(int a,int b)" << endl;
	}
public:
	static int mA;
};
int Father::mA = 10;

class Son :public Father
{
public:
	/*static void func()
	{
		cout << "Son func()" << endl;
	}*/
	//static int func()
	//{
	//	cout << "int func" << endl;
	//	return 0;
	//}
public:
	static int mA;
};
int Son::mA = 20;
void test01()
{
	Son s;
	cout << s.mA << endl;
	s.Father::mA = 200;
	cout << Father::mA << endl;
	cout << &(s.Father::mA) << endl;
	cout << &(Father::mA) << endl;
	s.func();
	s.func(10);
	s.func(10, 20);
}
int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

1.6 非自动继承的函数(了解)

构造,析构,赋值函数都不能被继承

1.7 多继承(了解)

1.多继承是一个类有两个以上的父类
2.多继承的问题是,当父类中有同名成员时,子类中会产生二义性问题

1.8 菱形继承(重点)

1.虚基类
被虚继承的基类叫虚基类
2.菱形继承的问题
两个父类中有祖类中的数据,然后子类会继承两个父类的数据,会产生二义性问题
3.虚继承
父类虚继承祖类,用virtual关键字
4.虚继承的原理
​ 1.编译给类添加了一个指针,指针指向类似于表的组织,该表记录了该指针距离变量的偏移量
​ 2.当子类多继承两个父类,那么只有一份成员变量,然后有两个指针,只有一份成员变量,所以不会产生二义性

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//爷爷
//被虚继承的基类叫虚基类
class Animal
{
public:
	Animal()
	{

	}
public:

};
//用虚继承的方法解决菱形继承中的二义性问题
//虚继承
class Sheep : virtual public Animal
{

};
//虚继承
class Camel :virtual public Animal
{
	/*
	class Camel     size(8):
	+---
	0      | {vbptr}
	+---
	+--- (virtual base Animal)
	4      | mA
	+---

	Camel::$vbtable@:
	0      | 0
	1      | 4 (Cameld(Camel+0)Animal)
	*/
};

class SheepCamel :public Sheep, public Camel
{
public:

};

void test()
{
	Camel c;
	cout << sizeof(c) << endl;


}

void test02()
{
	Sheep s;


	//1.&s;
	//2.(int*)&s;强转为int*类型
	//3.*(int*)&s;//获取指针中的地址
	//4.(int *)*(int*)&s;//指向表的首地址
	//5.(int *)*(int*)&s+1;//指向了表存储偏移量的地址
	//6.*((int *)*(int*)&s+1)//这就是偏移量
	cout << *((int*)*(int*)&s + 1) << endl;

	//1.&s
	//2.(char*)&s;
	//3.(char*)&s+*((int *)*(int*)&s + 1)
	//4.把类型转换为Animal指针类型
	//cout << ((Animal*)((char*)&s + *((int *)*(int*)&s + 1)))->mA << endl;


}
class A
{
public:
	int a;
};
class B :public A
{
public:

};
class C :public B
{

};
void test03()
{
	C c;
	c.a;
}
int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

1.9 动态联编和静态联编(重点难点)

1.静态联编

编译器会根据函数调用的对象类型,在编译阶段就确定函数的调用地址,这就是静态联编(早绑定)

2.虚函数

在普通成员函数前面加virtual,该函数变为虚函数,是告诉编译器这个函数要晚绑定

3.动态联编

在运行阶段才确定调用哪个函数(晚绑定),

4.动态编译的作用,可以晚绑定函数调用地址,这样可以扩展功能,不修改前面的代码的基础上进行项目的扩充

5.类型转换问题

​ 1.子类转换成父类(向上转换):编译器认为指针的寻址范围缩小了,所以是安全的

​ 2.父类转换成子类(向下转换);编译器认为指针的寻址范围扩大了,不安全

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Animal
{
public:
	//虚函数
	
	virtual void speak()
	{
		cout << "Animal speak " << endl;
	}
};

class Dog :public Animal
{
public:
	 void speak()
	{
		cout << "Dog speak " << endl;
	}
};

class Dog1 :public Animal
{
public:
	void speak()
	{
		cout << "Dog1 speak " << endl;
	}
};

class Dog2 :public Animal
{
public:
	void speak()
	{
		cout << "增加技能 " << endl;
	}
};

//业务层
void doLogin(Animal *animal)//Animal *animal=dog;
{
	animal->speak();
}
void test01()
{
	Animal an;
	an.speak();//在编译阶段就确定了调用speak这个函数
}
void test02()
{
	Dog *dog = new Dog;
	doLogin(dog);

	Dog1 *dog1 = new Dog1;
	doLogin(dog1);

	Dog2 *dog2 = new Dog2;
	doLogin(dog2);
}

int main()
{
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值