先看代码(很简单的):
先看代码(很简单的):
             class baseclass
    {
public int a;
public int b;
public virtual void  inc()
                           {
a = -a;
b = -b;
Console.WriteLine("Call base::inc()");
Console.WriteLine();
}
public baseclass()
{
a = 0;
b = 0;
Console.WriteLine("Call base().");
Console.WriteLine();
}
public baseclass(int va , int vb)
{
a = va;
b = vb;
Console.WriteLine("Call base(int va , int vb).");
Console.WriteLine();

public int add()
{
inc();
Console.WriteLine("Call base:add(int va , int vb).");

return a + b;
}
} class sub:baseclass
{
public override void  inc()
{
a ++;
b ++;
Console.WriteLine("Call SUB::inc()");
Console.WriteLine();
}
public sub():base()
{
Console.WriteLine("Call SUB()");
Console.WriteLine();
}
public sub(int va , int vb):base(va , vb)
{
Console.WriteLine("Call SUB(va , vb)");
Console.WriteLine(); }
}sub继承自baseclass
public class test
{
public static void Main()
{
int ret;

baseclass base1;
sub sub2 = new sub(1, 1);
base1 = (baseclass)sub2;//在此进行了显式类型转换
ret = base1.add();//还是调用add方法还是调用sub:inc()
if(base1 is sub)//测试条件为true
{
Console.WriteLine("base1 is sub");
Console.WriteLine("ret = {0}" , ret);
Console.WriteLine();
}
}
}
我想问
1.为何进行了显式类型转换,ret = base1.add()还是调用sub:inc(),(base1 is sub)为True?
2.有没有方法把派生类对象完完全全转换成基类对象?

解决方案 »

  1.   

    我想问一下,既然是继承,可为什么还在这样写:
    public sub():base()
    {
    ......
    }
    public sub(int va , int vb):base(va , vb)
    {
    ......
    }
    定义成员之后的base(va,vb)是什么意思?
      

  2.   

    定义成员之后的base(va,vb)是什么意思?
    -------------------------------------调用基类的构造函数。
      

  3.   

    wljjacob(千百) :不好意思,借你的宝地用一下。
      

  4.   

    base1的类型是定义的时候决定的,(.net是解释型语言,不知道是否能说是编译时候决定的)
    base1指向的对象是sub类的实例,这个操作是运行时决定的。
    根据多态原则,base1.Add调用baseclass的add函数,下面
    if(base1 is sub)  是判断引用的对象是什么类型,这里判断的是对象,不是引用本身。引用还是基类的没错。但这个对象是用sub实例化的。
      

  5.   

    因为派生类不能继承直接基类构造函数
    在声明派生类构造函数的时候,
    可以通过base关键字调用直接基类构造函数,并另外可以新增字段的值
      

  6.   

    (base1 is sub)为True?是正确的,因为你使base1与sub2指向的同一个地址
                              base1.add()也是调用的sub 类继承下来的add()方法;没有必要把派生类对象完完全全转换成基类对象,你直接定义基类对象不就可以了吗?
      

  7.   

    楼上的不要乱说。base1.add()调用的是基类的。不信你改改他代码就明白了。
    基类的add改一下,改为:
    public int add(int i)
    {
    inc();
    Console.WriteLine("Call base:add(int va , int vb).");

    return a + b + i;
    }
      

  8.   

    结合上面的讨论,偶又把代码整理了一下,添加了楼上wuyazhe(我的宝贝叫阿刺)所说的测试:
    class baseclass
    {
    public int a;
    public int b;
    public virtual void  inc(){
    a = -a;
    b = -b;
    Console.WriteLine("Call base::inc()");
    Console.WriteLine();
    }
    public baseclass()
    {
    a = 0;
    b = 0;
    Console.WriteLine("Call base().");
    Console.WriteLine();
    }
    public baseclass(int va , int vb)
    {
    a = va;
    b = vb;
    Console.WriteLine("Call base(int va , int vb).");
    Console.WriteLine();

    public int add()
    {
    inc();
    Console.WriteLine("Call base:add(int va , int vb).");

    return a + b;
    }
    } class sub:baseclass
    {
    public override void  inc()
    {
    a ++;
    b ++;
    Console.WriteLine("Call SUB::inc()");
    Console.WriteLine();
    }
    public sub():base()
    {
    Console.WriteLine("Call SUB()");
    Console.WriteLine();
    }
    public sub(int va , int vb):base(va , vb)
    {
    Console.WriteLine("Call SUB(va , vb)");
    Console.WriteLine(); }
    public new int  add()
    {
    inc();
    Console.WriteLine("Call sub:add(int va , int vb).");

    return -(a + b);
    }
    }public class test
    {
    public static void Main()
    {
    int ret;

    baseclass base1;
    baseclass base2 = (baseclass)(new sub(1,1));
    sub sub2 = new sub(1, 1);
    base1 = (baseclass)sub2;
    ret = base1.add();
    if(base1 is sub)
    {
    Console.WriteLine("base1 is sub");
    Console.WriteLine("ret = {0}" , ret);
    Console.WriteLine();
    }
    ret = base2.add();
    if(base2 is sub)
    {
    Console.WriteLine("base2 is sub");
    Console.WriteLine("ret = {0}" , ret);
    Console.WriteLine();
    }
    }
    }运行结果如下:Call base(int va , int vb).Call SUB(va , vb)Call base(int va , int vb).Call SUB(va , vb)Call SUB::inc()Call base:add(int va , int vb).
    base1 is sub
    ret = 4Call SUB::inc()Call base:add(int va , int vb).
    base2 is sub
    ret = 4Press any key to continue
    可见base1与base2行为完全一样.base1.add()与base2.add()均调用base:add(),而base:add()又调用sub:inc().因为base:add()方法未声名为virtual,sub:add()也未声名为override.而inc()被声名为virtual,且被重载.将add()改为virtual,结果显示sub:add()被调用.
    base1与base2为baseclass引用,但引用的对象为sub类型对象.
    对吗?
    但我比较困惑的是baseclass base2 = (baseclass)(new sub(1,1));与base1 = (baseclass)sub2;都进行了显式转换,它们引用的对象还是sub类型对象.这一点好像与C++中不同,比如在C++中:
    (base:inc()是virtual函数,在sub类中重载)
    base* pbase2;
    sub sub3(1 , 1);
    pbase2 = &(base)sub3;
    ret = pbase2->add();//add()调用base:inc()
    cout<<"ret = "<<ret<<endl<<endl;C#中有没有方法能达到同样的效果呢?
      

  9.   

    vc测试结果:
    base construct function with two Variables.
    Call child construct function with two Variables.
    base construct function with two Variables.
    Call child construct function with two Variables.
    Call child::inc()///////////////这里也调用的是子类的,不是基类的。
    Call base:add(int va , int vb).
      

  10.   

    #include <iostream.h>
    #include <stdlib.h>class BaseClass
    {
    public:
    virtual void inc()
    {
    a*=-1;
    b*=-1;
    cout<<"base inc";
    } BaseClass()
    {
    cout<<"base construct function without any Variable."<<endl;
    } BaseClass(int a,int b)
    {
    this->a = a;
    this->b = b;
    cout<<"base construct function with two Variables."<<endl;
    } int add()
    {
    inc();
    cout<<"Call base:add(int va , int vb)."<<endl;
    return a + b;
    }protected:
    int a;
    int b;
    };class Child:BaseClass
    {
    public:
    Child():BaseClass()
    {
    cout<<"Call child construct function without any Variable."<<endl;
    }

    Child(int a,int b):BaseClass(a,b)
    {
    cout<<"Call child construct function with two Variables."<<endl;
    } void inc()
    {
    a ++;
    b ++;
    cout<<"Call child::inc()"<<endl;
    } int add()
    {
    inc();
    cout<<"Call child:add(int a , int b)."<<endl;

    return -(a + b);
    }
    };int main()
    {
    int ret = 0;

    BaseClass *pBase1 = NULL;
    BaseClass *pBase2 = (BaseClass*)new Child(1,1);
    Child *child = new Child(1,1);
    pBase1 = (BaseClass*)child;
    ret = pBase1->add();
    system("pause");
    return 0;
    }
      

  11.   

    基类,子类对象都保存有一个虚汗数表,类型转换后,改变的是运行时的类型和调用方法,但当执行到基类Add函数中Inc的时候,这个函数的指针(.net里的委托)所指向的函数是在执行构造函数时生成的。依然是找到子类对象的虚函数表中的Inc,所以调用的还是子类的。不是基类。
      

  12.   

    你上面做的只是指针类型的转换,结果与预期的无异.
    试试这一句(在你的程序中):
    pBase1 = &(BaseClass)(*child);ret = pBase1->add();
      

  13.   

    终于明白了。-_-,.net无法操作对象本身,只能堆引用操作。关注一下,等你的结果。