访问派生类对象的字段,C ++与Java

时间:2016-05-26 10:21:09

标签: java c++ inheritance

如果在将此对象赋值给java中的基类类型的变量后访问派生类对象的字段,则会得到预期的行为,即打印字段的派生类的值。在字段的c ++值中,打印属于基类。

在Java中,按预期打印6:

class Ideone
{

    static class A {
        static int a = 7;
    }
    static class B extends A {
        static int b = 6;
    }
    public static void main (String[] args) throws java.lang.Exception
    {

        A a = new B();
        System.out.println(((B)a).b);
    }
}

在C ++中,打印出7:

#include <iostream>
using namespace std;

class Base {
    int i = 7;
public:

    Base(){
        std::cout << "Constructor base" << std::endl;
    }
    ~Base(){
        std::cout << "Destructor base" << std::endl;
    }
    Base& operator=(const Base& a){
        std::cout << "Assignment base" << std::endl;
    }
};

class Derived : public Base{
public:
    int j = 6;
};

int main ( int argc, char **argv ) {
    Base b;
    Derived p;
    cout << p.j << endl;
    b = p;
    Derived pcasted = static_cast<Derived&>(b);
    cout << pcasted.j << endl;
    return 0;
}

是否有可能在c ++中实现类似的行为(打印6)。

4 个答案:

答案 0 :(得分:5)

  

是否有可能在c ++中实现类似的行为(打印6)。

可以肯定的是,只要你做与Java相同的事情。

你必须记住,即使Java语法相似,它也不相同。在Java中,语句A a = new B();创建一个基本类型的引用,绑定到派生类型。 ((B)a)然后将引用的类型转换为派生类。

在c ++中,Base b;不是引用变量。将派生对象复制分配给此变量将复制派生对象的基础子对象。此语言功能称为切片。只需使用引用就可以获得与Java代码类似的语义:

Base& b = p;

如果通过Base引用访问具体类型为Derived&的对象,则会调用未定义的行为。

P.S。尽管返回类型为非void,但赋值运算符不会返回任何内容。没有返回有未定义的行为。

答案 1 :(得分:3)

在C ++代码中,b = p;slicingp复制到bb实际上仍为Base。然后static_cast<Derived&>(b)将失败并导致UB。

您可以使用引用或指针,让b实际上指向Derived。然后可以将其下载到Derived

int main ( int argc, char **argv ) {

    Derived p;
    Base& b = p;
    cout << static_cast<Derived&>(b).j << endl;
    return 0;
}

LIVE

答案 2 :(得分:2)

如果您的C ++代码甚至接近于等同于您的Java代码,那么您的问题可能会有意义。它不是。即使它们是用同一种语言编写的,两个非等价的代码段也会产生不同的结果也就不足为奇了。

表单的main()

int main ( int argc, char **argv )
{
    Base *b = new Derived;

    std::cout << ((Derived *)p)->j << endl;
    return 0;
}

(大约)等同于Java代码,允许Java在C ++中混合使用这些东西的概念,称为指针和引用。它会给你你期望的结果。

将语句std::cout << ((Derived *)p)->j << endl更改为等效(在C ++中)std::cout << (*((Derived *)p)).j << endl,这可能是对Java代码的更直译的解释。

实际上你的main()函数无论如何都会产生未定义的行为,所以所有的赌注都是关闭的。这条线

Derived pcasted = static_cast<Derived&>(b);

将对b的引用转换为对Derived的引用。由于b不属于Derived类型,因此pcasted的分配将b视为Derived,如果不是firebase use --clear。这给出了未定义的行为。

答案 3 :(得分:1)

代码差异:

  • 静态和非静态成员变量
  • 堆栈对象与堆(引用)对象
  • 在Stack-object的C ++中进行对象切片,在Java中使用简单的类型转换。

直接将苹果与橘子比较!