#include "iostream"
#include "string.h"
/************************类的封装**********************************/
//结构体默认是公有的,类默认是私有的
//私有类
class Student {
int age;
char sex;
double score;
public:
//封装起来变量取值方法,对于c++由于有指针不需要这么做
void setScore(double score) {
this->score = score;
}
};
//公有类,相当于struct
class Student1 {
public:
int age1;
char sex1;
double score1;
};
//通过指针访问私有成员,直接访问对象地址
class Student2 {
int age2;
char sex2;
double score2;
};
/************************继承**********************************/
//第一个类wood,基类,父类
class wood {
char name[20];
int length;
public:
wood(char* n, int len) {
strcpy(name, n);
length = len;
}
void show() {
std::cout << "这是一根" << length << "长的" << name;
}
};
//继承,子类继承类
//子类继承父类会自动拥有父类所有成员;
class desk:public wood {
public:
//继承子类的构造函数
desk(char*n, int len) :wood(n, len) {
};
};
/************************多态**********************************/
//大学生,小学生,中学生都有学习功能,但是学习方式不同,这种不一样专业叫多态
/***************number1**********************/
class student {
public:
student(){
};
void study() {
std::cout << "学生学习!" << std::endl;
};
};
//虽然都继承了基类,但是学习方式都一样
class CollegeStudent:public student {
};
class MiddleStudent:public student {
};
class PupilStudent:public student {
};
/***************number2**********************/
//描述不同学习具备不同特性用多态
//多态本质就是:函数重写:1.基类函数修饰为虚函数:virtual修饰;2.派生类重写这个函数
class student1 {
public:
int n;
student1() {
};
//基函数修饰为虚函数
virtual void study1() {
std::cout << "学生学习!" << std::endl;
};
//基函数修饰为虚函数
virtual void nstudy1() {
std::cout << "学生不学习!" << std::endl;
};
};
//虽然都继承了基类,但是学习方式都一样
class CollegeStudent1 :public student1 {
public:
//继承函数重写
void study1() {
std::cout << "大学生学习!" << std::endl;
};
};
class MiddleStudent1 :public student1 {
public:
//继承函数重写
void study1() {
std::cout << "中学生学习!" << std::endl;
};
};
class PupilStudent1 :public student1 {
public:
//继承函数重写
void study1() {
std::cout << "小学生学习!" << std::endl;
};
};
/***************number3**********************/
//多态的指针实现
void use(student1* p) {
p->study1();
}
/************************主函数**********************************/
int main()
{
/****************私有类***********************************/
//会报错
Student s;
s.score1 = 99.99; //私有成员不能根据对象名访问(封装)
//不会报错
s.setScore(99.99); //封装起来的变量赋值方法,由于C++有指针,此方法一般不用
/****************公有类**********************************/
Student1 s1;
s1.score1 = 99.99;
/********************私有类指针*************************/
//只要知道类里面数据怎么存储,就可以根据内存操作封装变量
//指着中存着什么类型就要将类型强制转换为(什么*)然后进行操作;
Student2 s2;
int *p =(int *) &s2; //强制类型转化
*p = 18; //此时age2里边的值变为18;
p++;
*(char *)p = 'X'; //此时sex2里边的值变为X;
(char*)p++;
*(double *)p = 88.88;//此时score2里边的值变为88.888;
/********************指针*************************/
int n = 10; //int类型的变量,n绑定4个字节的内存段
int m = 20;
&n; //得到n的首地址
int* p; //定义一个变量:保存一个指针,这个指针是int类型变量的首地址
p = &n; //指针变量指向n
*p ; //解引用,根据地址查找内存段
*p = 100; //此时n=100;
p -= 3; //不同编译器不同,变量存在堆栈
*p; //此时输出的是m的值为20;
*p = 200; //std::cout<<m<<std::endl;此时输出的是m为200
/************************继承************************************/
wood w("yueji", 40);
w.show();
desk dd("zhuzi",60);
dd.show();
/************************多态**********************************/
//所有学习方式都一样,体现不出差异性
student ts;
CollegeStudent cs;
MiddleStudent ms;
PupilStudent ps;
ts.study();
cs.study();
ms.study();
ps.study();
//想要体现出差异性就用多态
student1 ts1;
CollegeStudent1 cs1;
MiddleStudent1 ms1;
PupilStudent1 ps1;
ts1.study1();//打印出“学生学习”
cs1.study1();//打印出“大学生学习”
ms1.study1();//打印出“中学生学习”
ps1.study1();//打印出“小学生学习”
//多态指针实现
use(&ts1);//打印出“学生学习”
use(&cs1);//打印出“大学生学习”
use(&ms1);//打印出“中学生学习”
use(&ps1);//打印出“小学生学习”
/***************多态底层实现:虚函数表*****************/
//1.如果类中有虚函数,类的大小多出来4个字节
std::cout << sizeof(student) << std::endl; //当没有有virtual时大小为4
std::cout << sizeof(student1) << std::endl;//当有virtual时大小为8
student1 s1;
//将s1加入断点查看发现s1中存在一个_vfptr,就是一个指针变量,指向一个指针数组,所以叫虚函数表(数组)
//对象指针指向虚函数,有几个虚函数就指向几个数组,一个数组放置一个虚函数(这个数组就叫做虚函数表)
//如果不是虚函数不会保存到对象里边
//2.这四个字节是一个指针变量
//3.这个指针变量指向一个数组(虚函数表)
//4.验证
//s1指向了虚函数表,故s1中存放的是虚函数表中的首地址,*(&s1)就可以得到虚函数表的首地址,还需要强制类型转换
std::cout << &s1 << std::endl;
std::cout << "虚函数表的地址" << *((int*)&s1) << std::endl;//虚函数表的首地址拿到
//再次解引用,从首地址中拿到虚函数表中的第一个元素
int *p = (int*)*((int*)&s1);//拿到虚函数表首地址
int *p1 = (int*)*((int*)*((int*)&s1));//拿到数组即虚函数表中的第一个元素
//找出函数指针类型
typedef void(*FUNC)();
FUNC f = (FUNC)p1;
f(); //输出学生学习
p++;
int* p2 = (int*)*p;//虚函数表中第二个元素地址
FUNC f = (FUNC)p2;
f(); //输出学生玩
//继承过来的函数会将虚函数表同时继承过来,但是首地址不一样,因为函数重写
//5.派生类继承基类,会继承基类虚函数表中的所有元素
//6.如果派生类重写,会用重写的函数覆盖继承过来的虚函数表中元素
CollegeStudent1 Co;
}
关于类的封装继承多态的一个简单复习笔记
最新推荐文章于 2022-05-17 16:30:13 发布