新人关于里氏转换中的一些问题

weixin_41088766 2017-12-11 07:42:13
比如说我现在定义了两个类
Person类 父类
Student类 子类
在里氏转换的过程中,我们要先
Student stu = new Student();
Person per = new Person();
per = stu;//把Student的对象赋值给父类
Student stu = (Student)per; //把per父类强制转换成子类
那么我现在的问题有以下
1) 在Person per = new student(); 过程中,既然是Student的对象赋值给父类,那么是不是把子类对象stu的内存地址给了父类per,然后父类per指向了子类stu的内存地址? 那么为什么我测试的时候不能读取到子类中的内容呢?
2) 里氏转换到底有什么用呢?
3) 为什么我们能把父类定义成数组来接收子类对象呢? 如:Person[] perArry = {new student()}
...全文
290 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
秋的红果实 2017-12-12
  • 打赏
  • 举报
回复
1)这样处理下,就可以访问了:

class Person
{
    public virtual void printType(){}
    public string beType { set; get; }

}
class Student:Person
{
    public override void printType()
    {
        MessageBox.Show(beType);
    }
}
private void button1_Click(object sender, EventArgs e)
{
    Person pre = new Student() { beType = "the student" };
    pre.printType();

}

Person pre = new Student() { beType = "the student" }; 在堆上开辟了块空间,pre保存了该空间的首地址 2)里氏转换原则,讲得是结构设计原则,和你的问题无关。大意是:父类工作的地方,可以用其子类替代之。本质是说子类没有改变父类的功能,反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则。应该讲得很明白了。 用在软件结构设计方面 3)和Person pre = new Student() { beType = "the student" };一样
weixin_41088766 2017-12-12
  • 打赏
  • 举报
回复
引用 10 楼 From_TaiWan 的回复:
开闭原则,自己搜下,大意是只能增加功能,而不能修改原来的功能 例如计算器的问题,假设只是两个数运算,不合法等略去 你要是写成

if(Add)
{
    return a+b;
}
else if(Substraction)
{
    return a-b;
}

现在要增加a*b的算法,是不是要再加一个else if(Multiplacation),也就是改动了原来的代码 可以这样,

//基类和接口不动,无需修改
class Operation
{
    public int Number_one { set; get; }
    public int Number_two { set; get; }

}
interface add_Interface
{
    int add();
}

//加法运算过来,直接继承上面不动的两个东西,并将运算封装到一个类中
class Add:Operation,add_Interface
{
    //some functions...............
    public int add()
    {
        return Number_one - Number_two;
    }
}

//其他运算过来,增加运算的新类就可以了,无需动基类和接口

//调用
Add add = new Add();
add.Number_one = 1000;
add.Number_two = 100;
MessageBox.Show(add.add().ToString());

我这个,连个工厂模式都不是,但似乎可以解决问题,当然现实中还要考虑很多。 临时想了这个思路,可能不好,欢迎大牛指正
谢谢!
白衣如花 2017-12-12
  • 打赏
  • 举报
回复
里氏替换原则,不是类型转换操作。。。 是面向对象的一个设计原则,指子类能替换掉基类。 比如一个装水果的篮子,我们当然可以放苹果和梨子 比如要想从此过,留下买路钱。当然人民币,美元都是可以的。 例子中:水果和钱是父类,苹果和梨子,人民币和美元是子类,篮子和强盗接受父类的输入,肯定能用子类来替换
  • 打赏
  • 举报
回复
里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现。
LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,
基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

这个指的是任何可以使用基类的地方,传递子类进去也应该正确
你这个赋值过程只是继承应有的功能,而不是 里氏替换原则 想要解决的问题
wanghui0380 2017-12-12
  • 打赏
  • 举报
回复
不可说,说不得 技术实现你可以看《你必须知道的net》 至于意义这个是设计原则,是哲学和方法学。说不得,你自己领悟。如果不嫌啰嗦你可以去看《冒号课堂》
秋的红果实 2017-12-12
  • 打赏
  • 举报
回复
接口名不对,改成Operation_Interface
秋的红果实 2017-12-12
  • 打赏
  • 举报
回复
开闭原则,自己搜下,大意是只能增加功能,而不能修改原来的功能 例如计算器的问题,假设只是两个数运算,不合法等略去 你要是写成

if(Add)
{
    return a+b;
}
else if(Substraction)
{
    return a-b;
}

现在要增加a*b的算法,是不是要再加一个else if(Multiplacation),也就是改动了原来的代码 可以这样,

//基类和接口不动,无需修改
class Operation
{
    public int Number_one { set; get; }
    public int Number_two { set; get; }

}
interface add_Interface
{
    int add();
}

//加法运算过来,直接继承上面不动的两个东西,并将运算封装到一个类中
class Add:Operation,add_Interface
{
    //some functions...............
    public int add()
    {
        return Number_one - Number_two;
    }
}

//其他运算过来,增加运算的新类就可以了,无需动基类和接口

//调用
Add add = new Add();
add.Number_one = 1000;
add.Number_two = 100;
MessageBox.Show(add.add().ToString());

我这个,连个工厂模式都不是,但似乎可以解决问题,当然现实中还要考虑很多。 临时想了这个思路,可能不好,欢迎大牛指正
秋的红果实 2017-12-12
  • 打赏
  • 举报
回复


引用 7 楼 weixin_41088766 的回复:
[quote=引用 5 楼 From_TaiWan 的回复:] 1)这样处理下,就可以访问了:

class Person
{
    public virtual void printType(){}
    public string beType { set; get; }

}
class Student:Person
{
    public override void printType()
    {
        MessageBox.Show(beType);
    }
}
private void button1_Click(object sender, EventArgs e)
{
    Person pre = new Student() { beType = "the student" };
    pre.printType();

}

Person pre = new Student() { beType = "the student" }; 在堆上开辟了块空间,pre保存了该空间的首地址 2)里氏转换原则,讲得是结构设计原则,和你的问题无关。大意是:父类工作的地方,可以用其子类替代之。本质是说子类没有改变父类的功能,反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则。应该讲得很明白了。 用在软件结构设计方面 3)和Person pre = new Student() { beType = "the student" };一样
本质是说子类没有改变父类的功能 = 我们只是把子类的对象装在了父类里面,所以没有改变父类的功能 反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则 = 我们可以在子类上写属性,或者方法,这样就达到了“新增功能”的目的 这两句我这样么解释正确吗? 但是这一句我并不是很懂:保证开闭原则。[/quote] 不是你那么理解的! 给你具体例子,你就可以理解了

class A
{
    public void method1()
    {
        MessageBox.Show("The method is in basic class");
    }
}
class B : A
{
    public void method2()
    {
        MessageBox.Show("The method is in inherited class");
    }
}

private void button1_Click(object sender, EventArgs e)
{
    A a1 = new A();
    a1.method1();

    A a2 = new B(); //子类B可以替代父类A工作
    a2.method1();
}

输出结果一样 而我上面写的例子(override),不满足里氏转换原则。我只是看见你说没法取到子类内容。 不过现实中,用override的例子不少
ourhouzi 2017-12-12
  • 打赏
  • 举报
回复
引用 7 楼 weixin_41088766 的回复:
[quote=引用 5 楼 From_TaiWan 的回复:] 1)这样处理下,就可以访问了:

class Person
{
    public virtual void printType(){}
    public string beType { set; get; }

}
class Student:Person
{
    public override void printType()
    {
        MessageBox.Show(beType);
    }
}
private void button1_Click(object sender, EventArgs e)
{
    Person pre = new Student() { beType = "the student" };
    pre.printType();

}

Person pre = new Student() { beType = "the student" }; 在堆上开辟了块空间,pre保存了该空间的首地址 2)里氏转换原则,讲得是结构设计原则,和你的问题无关。大意是:父类工作的地方,可以用其子类替代之。本质是说子类没有改变父类的功能,反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则。应该讲得很明白了。 用在软件结构设计方面 3)和Person pre = new Student() { beType = "the student" };一样
本质是说子类没有改变父类的功能 = 我们只是把子类的对象装在了父类里面,所以没有改变父类的功能 反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则 = 我们可以在子类上写属性,或者方法,这样就达到了“新增功能”的目的 这两句我这样么解释正确吗? 但是这一句我并不是很懂:保证开闭原则。[/quote] 开闭原则的定义是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。软件开发过程中,最不会变化的就是变化本身。产品需要不断地升级、维护,没有一个产品从第一版本开发完就再没有变化了,如果因为变化、升级和维护等原因需要对软件原有代码进行修改时,这就可能会将错误引入原本已经经过测试的旧代码中,破坏原有系统。因此,当软件需要变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现。那么如何确保原有软件模块的正确性,以及尽量少地影响原有模块,答案就是尽量遵守本章要讲述的开闭原则
weixin_41088766 2017-12-12
  • 打赏
  • 举报
回复
引用 5 楼 From_TaiWan 的回复:
1)这样处理下,就可以访问了:

class Person
{
    public virtual void printType(){}
    public string beType { set; get; }

}
class Student:Person
{
    public override void printType()
    {
        MessageBox.Show(beType);
    }
}
private void button1_Click(object sender, EventArgs e)
{
    Person pre = new Student() { beType = "the student" };
    pre.printType();

}

Person pre = new Student() { beType = "the student" }; 在堆上开辟了块空间,pre保存了该空间的首地址 2)里氏转换原则,讲得是结构设计原则,和你的问题无关。大意是:父类工作的地方,可以用其子类替代之。本质是说子类没有改变父类的功能,反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则。应该讲得很明白了。 用在软件结构设计方面 3)和Person pre = new Student() { beType = "the student" };一样
本质是说子类没有改变父类的功能 = 我们只是把子类的对象装在了父类里面,所以没有改变父类的功能 反过来是说子类只能在父类基础上“新增”功能,而不可以改动父类原有功能,保证开闭原则 = 我们可以在子类上写属性,或者方法,这样就达到了“新增功能”的目的 这两句我这样么解释正确吗? 但是这一句我并不是很懂:保证开闭原则。
xuzuning 2017-12-12
  • 打赏
  • 举报
回复
里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现。 Student : Person 正因为遵循了这个原则,所以你才可以将 Person per = new Person(); 写作 Person per = new Student(); 当然,当一个 Student 对象被当作 Person 对象使用时,Student 的非继承成员都是不可被 Person 访问的 你只有通过在 Student override(重写)Person 的方法来达到行为的多样性 这就是: LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时, 基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
weixin_41088766 2017-12-11
  • 打赏
  • 举报
回复
求大神帮帮忙

110,499

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧