子类(虚函数,非虚函数)重写父类的函数(虚函数,非虚函数)等4种情况下的输出

1.子类重写父类“虚函数”,子类也写“虚函数”

#include<iostream>
using namespace std;
class parent{
public:
	virtual void s(){
		cout<<"parent"<<endl;
	}
};
class son : public parent{
public:
	virtual void s(){
		cout<<"son"<<endl;
	}
};

int  main(){
	
	son s1;
//可以理解为,向下造型
	parent *p1=&s1;
//引用子类对象,相当于指向一个子类,输出为子类
	parent &ref=s1;
	p1->s();
	ref.s();

	//正常的
	son s2;
	parent p2;
	//向下造型
	parent *ptr=new son();
	s2.s();
	p2.s();
	ptr->s();


	return 0;
}

为了方便看代码,把代码不必要的部分删了
在这里插入图片描述

2.1.子类重写父类“虚函数”,子类“不是虚函数”

#include<iostream>
using namespace std;
class parent{
public:
	virtual void s(){
		cout<<"parent"<<endl;
	}
};
class son : public parent{
public:
 void s(){//去掉virtual
		cout<<"son"<<endl;
	}
};

int  main(){
	
	son s1;
//可以理解为,向下造型
	parent *p1=&s1;
//引用子类对象,相当于指向一个子类,输出为子类	
	parent &ref=s1;
	p1->s();
	ref.s();

	//正常的
	son s2;
	parent p2;
	//向下造型
	parent *ptr=new son();
	s2.s();
	p2.s();
	ptr->s();


	return 0;
}

可以看出与上面没什么区别,输出部分代码删除,输出结果为了好区分
在这里插入图片描述

3.父类不是虚函数,子类虚函数

#include<iostream>
using namespace std;
class parent{
public:
	 void s(){//去掉virtual
		cout<<"parent"<<endl;
	}
};
class son : public parent{
public:
    virtual void s(){
		cout<<"son"<<endl;
	}
};

int  main(){
	
	son s1;
//可以理解为,向下造型
	parent *p1=&s1;
//引用子类对象,相当于指向一个子类,输出为子类
	parent &ref=s1;
	p1->s();
	ref.s();

	//正常的
	son s2;
	parent p2;
	//向下造型
	parent *ptr=new son();
	s2.s();
	p2.s();
	ptr->s();


	return 0;
}

在这里插入图片描述

#include<iostream>
using namespace std;
class parent{
public:
	 void s(){//去掉virtual
		cout<<"parent"<<endl;
	}
};
class son : public parent{
public:
    void s(){//去掉virtual
		cout<<"son"<<endl;
	}
};

int  main(){
	
	son s1;
//可以理解为,向下造型
	parent *p1=&s1;
//引用子类对象,相当于指向一个子类,输出为子类
	parent &ref=s1;
	p1->s();
	ref.s();

	//正常的
	son s2;
	parent p2;
	parent *ptr=new son();//向下造型
	s2.s();
	p2.s();
	ptr->s();


	return 0;
}

在这里插入图片描述

总结

	parent *p1=&s1;//可以理解为,向下造型
	parent &ref=s1;//引用子类对象,相当于指向一个子类,输出为子类
	parent *ptr=new son();//向下造型

1.1这两句实现的方式是一样的,都是指向子类的对象(子类对象所在的地址),只有父类为虚函数时才调用子类的方法(重写父类的那些函数),其实第三句和第一句一样,都是指向一个子类对象

parent:                 son:
	***************			****************     s()   **  父类  s()*	//输出parent
    ***************	     	***************
	                        *  子类  s()*	//输出son
							***************

1.2每个子类对象都会有构造一个父类的区域,这个区域在子类自身成员的前面,于是用父类指针去指向子类对象时,会从子类对象的起始地址(就像数组的起始地址一样),查询,一旦查询到s(),则调用s(),理所应当子类中包装的那部分父类成员,将会被先访问
1.3,这就会问到,为什么son s2;s2.s()的结果是子类自己的s(),而不是父类的,同样的重复上述操作,重子类对象的首地址开始找,避开父类的那部分成员,直接去访问子类本身具有的那部分成员,于是找到的就是子类的s()
1.4其是虚函数也是这样,父类声明了虚函数后,子类对象中将无法拥有父类的虚函数(虚函数是动态编联,在程序执行时发现才运行“载入”,而对象的创建在程序运行前就已经创建好了(静态编联),子类构造出对象的当然没有父类的虚函数)
1.5普及一下:程序运行的整个过程
1.预处理:#include,#define,#line等,
2.编译:对文件进行翻译成汇编语言
3.汇编:把汇编语言翻译成机器语言(二进制)
4.连接:把有关文件连成一个整体
5.机器运行,首先把对象,静态成员,全局变量造好,然后开始,只有运行到相应的代码块,发现有父类虚函数才会把它载入

发布了70 篇原创文章 · 获赞 71 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43625764/article/details/103294093