VerySource

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3628|回复: 21

觉得c++里引用一个不好的地方

[复制链接]

1

主题

2

帖子

3.00

积分

新手上路

Rank: 1

积分
3.00
发表于 2020-1-5 10:40:01 | 显示全部楼层 |阅读模式
#include <iostream.h>

class A
{
public:
        int v;
        A() { }
        virtual void f() { cout << "A::f()" << endl; }
        virtual ~A() { }
};

class B : public A
{
public:
        B() { }
        void f() { cout << "B::f()" << endl; }
        ~B() { }
};

int main(int argc, char* argv[])
{
        A *pa = new B();
        pa->v = 1;
        A c;
        c.v = 2;

        A &ra = *pa;
        ra.f();
        ra = c;
        ra.f();

        delete pa;
        return 0;
}

上面程序将输出两行B::f()

为什么不把虚表也拷贝过去呢?这样如果不知道的话,往往就因为这样的机制而调试很久,
回复

使用道具 举报

0

主题

4

帖子

4.00

积分

新手上路

Rank: 1

积分
4.00
发表于 2020-1-5 19:54:01 | 显示全部楼层
这个与引用无关吧。C++中如果将对象按字节拷贝是不会将虚函数表指针一起拷进去的。除非硬来:unsigned char *p = (unsigned char*)pa;
    unsigned char *q = (unsigned char*)&c;
for(int i=0; i<sizeof(c); i++)
    p[i] = q[i];
回复

使用道具 举报

0

主题

73

帖子

46.00

积分

新手上路

Rank: 1

积分
46.00
发表于 2020-1-6 00:54:01 | 显示全部楼层
为什么不把虚表也拷贝过去呢?
既然是“拷贝”,而不仅仅是“指向”或“引用”,那还有什么多态可言?
总不能作为X类的对象拷贝过来,同时又调用Y类的函数吧。
回复

使用道具 举报

0

主题

4

帖子

4.00

积分

新手上路

Rank: 1

积分
4.00
发表于 2020-1-6 02:03:01 | 显示全部楼层
一看楼主就是没学过软件工程的。
回复

使用道具 举报

0

主题

73

帖子

46.00

积分

新手上路

Rank: 1

积分
46.00
发表于 2020-1-6 06:03:01 | 显示全部楼层
哦,是我没想清楚楼主的问题,乱说了。
一楼说得没错,“对象拷贝”是不影响虚表的。
ra本来在引用着一个B类的对象,这一点是不会变的。
ra = c;
这句只是修改了那个被引用着的对象的基类子对象而已。不能修改虚表,一旦修改了,那就是说它现在还是引用着一个b类对象(),却拥有着A类的虚表,那样,你后面那句:
delete pa;
就不灵了,不会准确地调用析构函数了,当类复杂的时候,很容易弄出内存泄露来。
回复

使用道具 举报

0

主题

4

帖子

4.00

积分

新手上路

Rank: 1

积分
4.00
发表于 2020-1-6 07:30:01 | 显示全部楼层
#include <stdlib.h>

int main(int argc, char* argv[])
{
        A *pa = new B();
        pa->v = 1;
        A c;
        c.v = 2;

        A &ra = *pa;
        ra.f();

/*
        unsigned char *p = (unsigned char*)pa;
    unsigned char *q = (unsigned char*)&c;

        for(int i=0; i<sizeof(c); i++)
                p[i] = q[i];
*/
        memcpy(pa, &c, sizeof(c));

        ra.f();

        delete pa;
        return 0;
}

我想这样大概就使楼主称心了吧。

这除了偶尔娱乐娱乐外真的没有其它任何意义。原本分配的类B对象,后来将A类对象成员拷进去。不过这也正常,可以作为某种特殊的初始化。
但后面就不对了,把虚函数表指针也拷进去,结果就是在原本类B中的对象运行时转为类A对象(名副其实的运行时类型转换-_-!)。那么现在ra引用的是类A对象还是类B对象呢?

A a;

B b;

b = a;的真正意义在于:将父类对象a的父类域成员按字节拷贝给子类B对象(这里假设等号没有重载)。如果将虚函数指针也一起拷给b,那就等于失去作为类B的资格了,即与A同化了。

版主晨星说得不错啊。
回复

使用道具 举报

0

主题

3

帖子

4.00

积分

新手上路

Rank: 1

积分
4.00
发表于 2020-1-6 08:54:01 | 显示全部楼层
赋值的语义是相对于对象来说的,而虚函数表则是相对于类来说的。既然赋值只是对对象进行操作,当然就不会自动进行被赋值对象的类型转换(赋值的过程中编译器也不知道所引用的对象的实际类型)。引用的类型所暗示的是用户操作引用对象的抽象形式,但它不会(也不应该)介入实际对象的类型的改变。
回复

使用道具 举报

0

主题

6

帖子

6.00

积分

新手上路

Rank: 1

积分
6.00
发表于 2020-1-6 17:00:01 | 显示全部楼层
呵呵,值得思考的题目,收藏先!!
回复

使用道具 举报

0

主题

15

帖子

13.00

积分

新手上路

Rank: 1

积分
13.00
发表于 2020-1-6 19:45:01 | 显示全部楼层
楼主对多态的机制还是不太熟啊
回复

使用道具 举报

1

主题

6

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
发表于 2020-1-9 02:09:01 | 显示全部楼层
奇怪,这个程序在g++上即使加-Wall参数也不报warnning???????

<<Thinking in C++>> vol.1 charpter 11

Once a reference is initialized to an object, it cannot be
changed to refer to another object. (Pointers can be pointed to
another object at any time.)

<<ISO C++ 14882-2003>> 8.5.3.2
A reference cannot be changed to refer to another object after initialization.

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

快速回复 返回顶部 返回列表