将一种类型的对象分配给另一种类型

时间:2012-06-19 16:35:58

标签: c++ variable-assignment

在下面的代码中有两个类。创建一个类型为2的对象,然后将其分配给第一类的指针。

在调用out函数时,调用第一类的out函数。

#include<iostream>
using namespace std;

class one
{
    public :
        void  out()
        {
            cout<<"one ";
        }
};

class two
{
    public : 
        void out()
        {
            cout<<"two ";
        }
};

int main()
{ 
    two dp[3];
    one *bp = (one *)dp;
    for (int i=0; i<3;i++)
    (bp++)->out();
}    

输出

one one one

根据我的输出应该是两个而不是一个。 当我们创建了类型2的对象时,该对象的内存位置包含了类2之外的函数的地址,那么为什么在赋值时,第一类被调用?

编辑 - 而且即使我们更改了第二类中的函数名称,输出也不会改变。

3 个答案:

答案 0 :(得分:4)

新手假设所有 C ++成员函数&#34;属于&#34;并不少见。对象。
如你所知,他们没有。

从概念上讲 - 精确的过程是编译器实现细节 - 您的out成员函数转换为&#34; free&#34;看起来像这样的函数:

void one_out(one* this) { cout << "one"; }
void two_out(two* this) { cout << "two"; }

对于非会员功能,这就是所有需要的。

当编译器看到

  (bp++)->out();

知道 bp是指向one的指针(它不知道你撒谎),所以它调用

one_out(bp++);

因为那是编译器的作用。

答案 1 :(得分:1)

你的机器上的输出可能是“一一”,但它可能很容易被炸毁,消失了&amp;得到你的冰淇淋,或发射导弹。您的代码唤起了未定义的行为。

class one
/*...*/

class two
/*...*/

请注意,onetwo是完全不相关的类。您未从two派生one,反之亦然。它们是完全不同的类型。

因此...

two dp[3];
one *bp = (one *)dp;
for (int i=0; i<3;i++)
    (bp++)->out();

此代码唤起未定义的行为*。 bp未指向one类型的对象,它指向类型为two的对象。鉴于上面的代码,你不能以这种方式转换指针。

(*注意:未定义的行为是指当对象实际上是one时尝试调用two方法时。转换本身不会引起未定义的行为。)

您正在使用的演员语法,(one *)dp是一个C风格的演员,在这个例子中归结为reinterpret_cast<one*>(bp);的等效。如果除了编写自我记录代码之外没有其他原因,最好使用reinterpret_cast这是你真正打算做的事情。

如果你真的想从one*获得two*,你有两种选择。

  1. 创建一个继承层次结构,以便您可以在不引起UB的情况下进行投射
  2. 创建转换运算符,以便您可以从one构建two,反之亦然。
  3. 在您的情况下,由于您循环遍历one个对象并尝试通过这些指针执行two方法,因此您最好的选择可能是#1以上。

    class one
    {
        public :
            virtual void  out()
            {
                cout<<"one ";
            }
    };
    
    class two : public one
    {
        public : 
            void out()
            {
                cout<<"two ";
            }
    };
    

    现在你的循环将起作用,代码将发出“两个两个”,而不是你实际看到的任何随机行为。

答案 2 :(得分:-3)

由于您的out()方法未声明virtual,因此会在对象的静态类型上调度它,而不是对象的运行时类型。

此外,两个类之间没有子类型关系,因此以这种方式分配指针是不正确的。