标签:
C#&C++多态问题简析
在学习C#面向对象时,对封装和继承基本上还是理解的,但是碰到多态,基本上就是记住了个父类引用指向子类对象,在很长时间内也是一直比较困惑。学习c++时,基本上算是有了一定了解。下面结合代码解释多态问题
首先是c#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DuoTai
{
class Father
{
public void FatherSayHello()
{
Console.WriteLine("Father");
}
}
class Son1:Father
{
public void Son1SayHello()
{
Console.WriteLine("Son1");
}
}
class Son2 : Father
{
public void Son2SayHello()
{
Console.WriteLine("Son2");
}
}
class Program
{
static void Main(string[] args)
{
Father f = new Son1();
//注1:f引用对象无法访问Son的函数SonSayHello
f.FatherSayHello();
//注2:子类引用可以调自己及父类的函数
Son1 s1 = f as Son1;
s1.Son1SayHello();
s1.FatherSayHello();
f = new Son2();
Son2 s2 = f as Son2;
s2.Son2SayHello();
////注3:下面问题会抛出异常
//Father ff = new Father();
//Son1 s11 = ff as Son1;
//s11.FatherSayHello();
//s11.Son1SayHello();
Console.Read();
}
}
}
运行结果想必大家还是很清楚的。
本人程序员一枚,没做过什么高大上的程序设计,但看这个多态案例,貌似没什么高深之处。就是声明一个父类引用,可以指向不同的子类实例。有一个疑问,子类引用为什么不能指向父类实例呢?不兜圈子,直接分析对象实例化过程来分析,上图:
很简单,当我们new一个子类对象时,首先会先new一个父类对象,可以这么理解,子类对象包含一个父类对象。
不管是子类引用还是父类引用,我们都可以理解为指针,存储在栈上,值为指向的堆上的对象内存地址。既然可以理解为指针,指针的类型决定解析方式。如上图,子类对象可以搜索到父类及子类的函数,而父类对象只能搜索到自己的函数,这样,上面C#代码中注1和注2也就很容易理解了。(※这里我们只是讨论多态问题,作用域问题,不再考虑范围之内,至于父类的private函数问题什么的,也就不要吐槽了。)
说到这里,子类引用为什么不能指向父类实例也就很明白了,假设我们声明子类引用,当我们调用自己的SonSayHello()方法时,但是父类实例并没有这个方法,我们就无法调用了。
上面的分析目前还只是我的一面之词,我需要用c++代码加以佐证,要不然别人该说我瞎扯了,废话不多说,直接上c++代码及运行结果
1.验证创建子类对象时会先创建父类对象,下图是运行结果。
2.用c++代码解释面向对象,以及c++面向对象与c#的不通
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<string>
using namespace std;
class Father
{
public:
Father();
~Father();
public:
void FatherSayHello();
};
Father::Father()
{
cout << "Father Created" << endl;
}
Father::~Father()
{
cout << "Father Deleted" << endl;
}
void Father::FatherSayHello()
{
cout << "Father" << endl;
}
class Son1:public Father
{
public:
Son1();
~Son1();
public:
void Son1SayHello();
void Son1SayName();
public :
char * name;
};
Son1::Son1()
{
cout << "Son1 Created" << endl;
}
Son1::~Son1()
{
cout << "Son1 Deleted" << endl;
}
void Son1::Son1SayHello()
{
cout << "Son1" << endl;
}
void Son1::Son1SayName()
{
cout << this->name << endl;
}
void main()
{
//验证创建子类对象时会同时创建父类对象
Son1 *ps1 = new Son1;
delete ps1;
//父类指针指向子类对象
Father *pf1 = new Son1;
delete pf1;
//子类指针不能指向父类对象
//Son1 *ps2 = new Father;//报错,原因同上面对C#面向对象的分析
//通过指针转换实现子类指针指向父类对象,这个不同于C#,
//Son1的Son1SayHello()调用成功的原因是类成员函数是存在共享区域的,成员变量是存在私有区域的
Father *pf2 = new Father;
Son1 *ps2 = reinterpret_cast<Son1 *>(pf2);
ps2->FatherSayHello();
ps2->Son1SayHello();
//加上这一段代码,程序会抛出异常,因为我们在调用Son1SayName()的时候
//要同时调用类的成员变量
//ps2->Son1SayName();
//为对函数共享,成员变量私有佐证,请看下面代码
//给对象指针复制nullptr后,函数仍然可以正常调用
Son1 * ps3 = nullptr;
ps3->Son1SayHello();
cin.get();
}
以上是个人分析总结,如有错误,敬请指正。
标签:
原文地址:http://www.cnblogs.com/aaron-song/p/4526437.html