【问题标题】:base class is a reference to another object基类是对另一个对象的引用
【发布时间】:2017-02-12 17:41:37
【问题描述】:

我刚刚遇到了一段对我来说似乎很奇怪的代码 sn-p(请参见下面的最小示例),derived::base 是对 base 类型的另一个对象的引用,有人可以帮我回答cmets中的问题?

class base{
public:
   int a;
   int b;
};

class derived : public base{
public:
   double c;
   void run(const base & bs){
     ((base &) *this) = bs; // what does this line do? 
                            // Is derived::base now a copy of bs? 
                            // If yes, but why not write ((base) *this) = bs?
                            // if not, then derived::base is a reference to bs, 
                            // then does it mean the memory of derived::base
                            // and members of derived are no longer contiguous?
     std::cout << "a = " << a << std::endl;

   }
};

附言

@LightnessRacesinOrbit 的 cmets 帮助解决了很多问题,但我只能接受一个答案帖子,最好是 @WhiZTiM

【问题讨论】:

  • 它所做的只是调用基类的复制构造函数,它将复制基类的成员(即a 和b)而不触及对象派生部分中的任何内容(即c)。我不明白为什么内存不再连续。
  • afaik 你永远无法保证对象成员存储在连续内存中,即使没有这种“仅复制基类成员”技巧。也许对“连续”的含义有些误​​解。您能否详细解释一下您对该代码的担忧之处?
  • @imreal,但如果调用复制构造函数,为什么不写((base) *this) = bs?
  • @tobi303,我担心的是,如果只是调用复制构造函数,为什么不直接写((base) *this) = bs或derived::base = bs呢?

标签: c++


【解决方案1】:
void run(const base & bs){
     ((base &) *this) = bs; 
     std::cout << "a = " << a << std::endl;
}

上面的代码可以分解为:

void run(const base & bs){
     base& base_of_this_instance = *this; 
     base_of_this_instance = bs;
     std::cout << "a = " << a << std::endl;
}

derived 对象的内存可以这样布局:

||  int a  |x|  int b  |y|  int c  ||   // <- x and y represents some hypothetical padding
||        base         |y|         ||   // <- We can slice `derived` and retrieve only base
||           derived               ||   // <- Memory consumed by derived

在您的derived::run 方法中,首先,获得对derived 的base 部分的引用,其次将base 分配给bs。该赋值将调用base 的复制赋值运算符。这意味着基础部分现在将保存 bs 中的任何内容的副本。

【讨论】:

  • 写成((base) *this) = bs会有什么不同?
  • @Allanqunzi:你得到了一个无用的临时副本。
  • ((base) *this) = bs 将简单地将bs 分配给派生的切片部分base。由于那个 sliced 部分是一个临时的未命名对象,它将在; 的末尾被破坏。实际上,您会浪费工作。 derived 不受影响
  • @LightnessRacesinOrbit,为什么它是临时的?我认为*this 将是对当前类的引用。
  • @Allanqunzi:因为这就是铸造的作用。 (base) 是演员。
【解决方案2】:

结果

((base &) *this)

是对基类的引用

你可以把它保存到一个变量中:

base& refToBase = ((base &) *this);

refToBase 是对同一个对象的引用,即 this

之后你就有了任务

refToBase = bs;

它将 bs 的值分配给 refToBase 对象

像这样:

int i = 10;
int p = 20;
int& refI = i;
int& refP = p;
refI = refP; // i == 20
p = 15; // p ==15 but i == 20

因此,在执行示例中的“奇怪代码”后,我们在 derived::a 和 derived::b 中拥有 bs.a 和 bs.b 的副本

derived::base和derived::c的内存还是一批

【讨论】:

  • 为什么不直接写((base) *this) = bs 或derived::base = bs?
  • @Allanqunzi:因为第一个创建的是临时副本,第二个是幻想
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 2018-03-19
  • 2013-02-18
  • 1970-01-01
相关资源
最近更新 更多