什么是对象切片?

发布于 2024-07-07 22:00:08 字数 29 浏览 16 评论 0原文

在 C++ 中,什么是对象切片以及何时发生?

In C++, what is object slicing and when does it occur?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

浅唱々樱花落 2024-07-14 22:00:08

“切片”是将派生类的对象分配给基类的实例,从而丢失部分信息 - 其中一些信息被“切片”掉。

例如,

class A {
   int foo;
};

class B : public A {
   int bar;
};

B 类型的对象有两个数据成员:foobar

那么如果您要这样写:

B b;

A a = b;

那么 b 中关于成员 bar 的信息就会在 a 中丢失。

"Slicing" is where you assign an object of a derived class to an instance of a base class, thereby losing part of the information - some of it is "sliced" away.

For example,

class A {
   int foo;
};

class B : public A {
   int bar;
};

So an object of type B has two data members, foo and bar.

Then if you were to write this:

B b;

A a = b;

Then the information in b about member bar is lost in a.

记忆で 2024-07-14 22:00:08

这里的大多数答案都无法解释切片的实际问题是什么。 他们只解释良性的切片情况,而不解释危险的情况。 假设与其他答案一样,您正在处理两个类 AB,其中 B (公开)派生自 一个。

在这种情况下,C++ 允许您将 B 的实例传递给 A 的赋值运算符(也传递给复制构造函数)。 这是可行的,因为 B 的实例可以转换为 const A&,这正是赋值运算符和复制构造函数所期望的参数。

良性情况

B b;
A a = b;

那里没有发生任何不好的事情 - 您请求一个 A 的实例,它是 B 的副本,而这正是您所得到的。 当然,a 不会包含 b 的某些成员,但是应该如何呢? 毕竟,它是一个 A,而不是 B,因此它甚至没有听说过这些成员,更不用说能够存储他们。

危险的情况

B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!

您可能会认为 b2 之后将是 b1 的副本。 但是,唉,事实并非如此! 如果您检查它,您会发现 b2 是一种弗兰肯斯坦生物,由 b1 的一些块(B 继承自的块)组成A),以及一些 b2 块(仅 B 包含的块)。 哎哟!

发生了什么? 嗯,默认情况下,C++ 并不将赋值运算符视为虚拟运算符。 因此,a_ref = b1 行将调用 A 的赋值运算符,而不是 B 的赋值运算符。 这是因为,对于非虚函数,声明(正式:静态)类型(即 A&)决定调用哪个函数,而不是实际(正式:动态)类型(可能是B,因为a_ref引用了一个B 的实例)。 现在,A 的赋值运算符显然只知道 A 中声明的成员,因此它只会复制这些成员,而将成员添加到 B 中> 不变。

解决方案

仅分配给对象的一部分通常没有什么意义,但不幸的是,C++ 没有提供内置方法来禁止这种情况。 但是,您可以自己推出。 第一步是使赋值运算符成为虚拟的。 这将保证调用的始终是实际类型的赋值运算符,而不是声明类型的赋值运算符。 第二步是使用dynamic_cast来验证分配的对象是否具有兼容的类型。 第三步是在(受保护的!)成员 assign() 中进行实际分配,因为 Bassign() 可能会想要使用 Aassign() 来复制 A 的成员。

class A {
public:
  virtual A& operator= (const A& a) {
    assign(a);
    return *this;
  }

protected:
  void assign(const A& a) {
    // copy members of A from a to this
  }
};

class B : public A {
public:
  virtual B& operator= (const A& a) {
    if (const B* b = dynamic_cast<const B*>(&a))
      assign(*b);
    else
      throw bad_assignment();
    return *this;
  }

protected:
  void assign(const B& b) {
    A::assign(b); // Let A's assign() copy members of A from b to this
    // copy members of B from b to this
  }
};

请注意,为了纯粹的方便,Boperator= 协变地覆盖了返回类型,因为它知道它正在返回 B。

Most answers here fail to explain what the actual problem with slicing is. They only explain the benign cases of slicing, not the treacherous ones. Assume, like the other answers, that you're dealing with two classes A and B, where B derives (publicly) from A.

In this situation, C++ lets you pass an instance of B to A's assignment operator (and also to the copy constructor). This works because an instance of B can be converted to a const A&, which is what assignment operators and copy-constructors expect their arguments to be.

The benign case

B b;
A a = b;

Nothing bad happens there - you asked for an instance of A which is a copy of B, and that's exactly what you get. Sure, a won't contain some of b's members, but how should it? It's an A, after all, not a B, so it hasn't even heard about these members, let alone would be able to store them.

The treacherous case

B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!

You might think that b2 will be a copy of b1 afterward. But, alas, it's not! If you inspect it, you'll discover that b2 is a Frankensteinian creature, made from some chunks of b1 (the chunks that B inherits from A), and some chunks of b2 (the chunks that only B contains). Ouch!

What happened? Well, C++ by default doesn't treat assignment operators as virtual. Thus, the line a_ref = b1 will call the assignment operator of A, not that of B. This is because, for non-virtual functions, the declared (formally: static) type (which is A&) determines which function is called, as opposed to the actual (formally: dynamic) type (which would be B, since a_ref references an instance of B). Now, A's assignment operator obviously knows only about the members declared in A, so it will copy only those, leaving the members added in B unchanged.

A solution

Assigning only to parts of an object usually makes little sense, yet C++, unfortunately, provides no built-in way to forbid this. You can, however, roll your own. The first step is making the assignment operator virtual. This will guarantee that it's always the actual type's assignment operator which is called, not the declared type's. The second step is to use dynamic_cast to verify that the assigned object has a compatible type. The third step is to do the actual assignment in a (protected!) member assign(), since B's assign() will probably want to use A's assign() to copy A's, members.

class A {
public:
  virtual A& operator= (const A& a) {
    assign(a);
    return *this;
  }

protected:
  void assign(const A& a) {
    // copy members of A from a to this
  }
};

class B : public A {
public:
  virtual B& operator= (const A& a) {
    if (const B* b = dynamic_cast<const B*>(&a))
      assign(*b);
    else
      throw bad_assignment();
    return *this;
  }

protected:
  void assign(const B& b) {
    A::assign(b); // Let A's assign() copy members of A from b to this
    // copy members of B from b to this
  }
};

Note that, for pure convenience, B's operator= covariantly overrides the return type, since it knows that it's returning an instance of B.

习ぎ惯性依靠 2024-07-14 22:00:08

如果您有一个基类 A 和一个派生类 B,那么您可以执行以下操作。

void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);

现在,wantAnA 方法需要 driven 的副本。 但是,派生 对象无法完全复制,因为类B 可能会发明不在其基类A 中的其他成员变量。

因此,为了调用 wantAnA,编译器将“切掉”派生类的所有附加成员。 结果可能是您不想创建的对象,因为

  • 它可能不完整,
  • 它的行为类似于 A 对象(类 B 的所有特殊行为都会丢失)。

If You have a base class A and a derived class B, then You can do the following.

void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);

Now the method wantAnA needs a copy of derived. However, the object derived cannot be copied completely, as the class B could invent additional member variables which are not in its base class A.

Therefore, to call wantAnA, the compiler will "slice off" all additional members of the derived class. The result might be an object you did not want to create, because

  • it may be incomplete,
  • it behaves like an A-object (all special behaviour of the class B is lost).
记忆消瘦 2024-07-14 22:00:08

这些都是很好的答案。 我只想在按值传递对象与按引用传递对象时添加一个执行示例:

#include <iostream>

using namespace std;

// Base class
class A {
public:
    A() {}
    A(const A& a) {
        cout << "'A' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am an 'A'" << endl; }
};

// Derived class
class B: public A {
public:
    B():A() {}
    B(const B& a):A(a) {
        cout << "'B' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am a 'B'" << endl; }
};

void g(const A & a) {
    a.run();
}

void h(const A a) {
    a.run();
}

int main() {
    cout << "Call by reference" << endl;
    g(B());
    cout << endl << "Call by copy" << endl;
    h(B());
}

输出为:

Call by reference
I am a 'B'

Call by copy
'A' copy constructor
I am an 'A'

These are all good answers. I would just like to add an execution example when passing objects by value vs by reference:

#include <iostream>

using namespace std;

// Base class
class A {
public:
    A() {}
    A(const A& a) {
        cout << "'A' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am an 'A'" << endl; }
};

// Derived class
class B: public A {
public:
    B():A() {}
    B(const B& a):A(a) {
        cout << "'B' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am a 'B'" << endl; }
};

void g(const A & a) {
    a.run();
}

void h(const A a) {
    a.run();
}

int main() {
    cout << "Call by reference" << endl;
    g(B());
    cout << endl << "Call by copy" << endl;
    h(B());
}

The output is:

Call by reference
I am a 'B'

Call by copy
'A' copy constructor
I am an 'A'
只有影子陪我不离不弃 2024-07-14 22:00:08

谷歌中“C++ 切片”的第三次匹配给了我这篇维基百科文章 http://en.wikipedia.org/wiki /Object_slicing 和这个(激烈,但前几篇文章定义了问题):http:// bytes.com/forum/thread163565.html

因此,当您将子类的对象分配给超类时。 超类对子类中的附加信息一无所知,并且没有空间来存储它,因此附加信息被“切掉”。

如果这些链接没有提供足够的信息来获得“好的答案”,请编辑您的问题,让我们知道您还在寻找什么。

Third match in google for "C++ slicing" gives me this Wikipedia article http://en.wikipedia.org/wiki/Object_slicing and this (heated, but the first few posts define the problem) : http://bytes.com/forum/thread163565.html

So it's when you assign an object of a subclass to the super class. The superclass knows nothing of the additional information in the subclass, and hasn't got room to store it, so the additional information gets "sliced off".

If those links don't give enough info for a "good answer" please edit your question to let us know what more you're looking for.

明月夜 2024-07-14 22:00:08

切片问题很严重,因为它可能导致内存损坏,并且很难保证程序不会受到这种情况的影响。 为了从语言中设计它,支持继承的类应该只能通过引用(而不是通过值)访问。 D 编程语言具有这个特性。

考虑类 A 和从 A 派生的类 B。如果 A 部分具有指针 p 和将 p 指向 B 的附加数据的 B 实例,则可能会发生内存损坏。 然后,当附加数据被切掉时,p 就指向垃圾。

The slicing problem is serious because it can result in memory corruption, and it is very difficult to guarantee a program does not suffer from it. To design it out of the language, classes that support inheritance should be accessible by reference only (not by value). The D programming language has this property.

Consider class A, and class B derived from A. Memory corruption can happen if the A part has a pointer p, and a B instance that points p to B's additional data. Then, when the additional data gets sliced off, p is pointing to garbage.

你另情深 2024-07-14 22:00:08

我看到所有答案都提到当数据成员被切片时对象切片发生。 这里我举一个方法不被重写的例子:

class A{
public:
    virtual void Say(){
        std::cout<<"I am A"<<std::endl;
    }
};

class B: public A{
public:
    void Say() override{
        std::cout<<"I am B"<<std::endl;
    }
};

int main(){
   B b;
   A a1;
   A a2=b;

   b.Say(); // I am B
   a1.Say(); // I am A
   a2.Say(); // I am A   why???
}

B(对象b)派生自A(对象a1和a2)。 b 和 a1 正如我们所期望的,调用它们的成员函数。 但从多态性的角度来看,我们不希望由 b 指定的 a2 不被覆盖。 基本上,a2仅保存b的A类部分,即C++中的对象切片。

为了解决这个问题,应该使用引用或指针

 A& a2=b;
 a2.Say(); // I am B

,或者

A* a2 = &b;
a2->Say(); // I am B

I see all the answers mention when object slicing happens when data members are sliced. Here I give an example that the methods are not overridden:

class A{
public:
    virtual void Say(){
        std::cout<<"I am A"<<std::endl;
    }
};

class B: public A{
public:
    void Say() override{
        std::cout<<"I am B"<<std::endl;
    }
};

int main(){
   B b;
   A a1;
   A a2=b;

   b.Say(); // I am B
   a1.Say(); // I am A
   a2.Say(); // I am A   why???
}

B (object b) is derived from A (object a1 and a2). b and a1, as we expect, call their member function. But from polymorphism viewpoint we don’t expect a2, which is assigned by b, to not be overridden. Basically, a2 only saves A-class part of b and that is object slicing in C++.

To solve this problem, a reference or pointer should be used

 A& a2=b;
 a2.Say(); // I am B

or

A* a2 = &b;
a2->Say(); // I am B
暖风昔人 2024-07-14 22:00:08

在 C++ 中,可以将派生类对象分配给基类对象,但反之则不行。

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

当派生类对象被分配给基类对象时,就会发生对象切片,派生类对象的附加属性被切片以形成基类对象。

In C++, a derived class object can be assigned to a base class object, but the other way is not possible.

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

Object slicing happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object.

爱格式化 2024-07-14 22:00:08

那么...为什么丢失派生信息是不好的呢? ...因为派生类的作者可能已经更改了表示形式,因此删除额外信息会更改对象表示的值。 如果派生类用于缓存对某些操作更有效的表示,但转换回基本表示的成本很高,则可能会发生这种情况。

还认为有人还应该提到你应该做什么来避免切片......
获取 C++ 编码标准、101 条规则指南和最佳实践的副本。 处理切片是#54。

它提出了一种稍微复杂的模式来完全处理这个问题:有一个受保护的复制构造函数、一个受保护的纯虚拟 DoClone 和一个带有断言的公共克隆,该断言将告诉您(进一步的)派生类是否无法正确实现 DoClone。 (Clone 方法对多态对象进行适当的深层复制。)

您还可以将复制构造函数标记为显式基类,以便在需要时允许显式切片。

So ... Why is losing the derived information bad? ... because the author of the derived class may have changed the representation such that slicing off the extra information changes the value being represented by the object. This can happen if the derived class if used to cache a representation that is more efficient for certain operations, but expensive to transform back to the base representation.

Also thought someone should also mention what you should do to avoid slicing...
Get a copy of C++ Coding Standards, 101 rules guidlines, and best practices. Dealing with slicing is #54.

It suggests a somewhat sophisticated pattern to fully deal with the issue: have a protected copy constructor, a protected pure virtual DoClone, and a public Clone with an assert which will tell you if a (further) derived class failed to implement DoClone correctly. (The Clone method makes a proper deep copy of the polymorphic object.)

You can also mark the copy constructor on the base explicit which allows for explicit slicing if it is desired.

狼性发作 2024-07-14 22:00:08

C++ 中的切片问题源于其对象的值语义,这主要是由于与 C 结构体的兼容性。 您需要使用显式引用或指针语法来实现大多数其他处理对象的语言中的“正常”对象行为,即对象始终通过引用传递。

简而言之,您可以通过将派生对象按值分配给基础对象来对对象进行切片,即剩余的对象只是派生对象的一部分。 为了保留值语义,切片是一种合理的行为,并且具有相对较少的用途,这在大多数其他语言中都不存在。 有些人认为它是 C++ 的一个特性,而许多人则认为它是 C++ 的怪癖/错误特性之一。

The slicing problem in C++ arises from the value semantics of its objects, which remained mostly due to compatibility with C structs. You need to use explicit reference or pointer syntax to achieve "normal" object behavior found in most other languages that do objects, i.e., objects are always passed around by reference.

The short answers is that you slice the object by assigning a derived object to a base object by value, i.e. the remaining object is only a part of the derived object. In order to preserve value semantics, slicing is a reasonable behavior and has its relatively rare uses, which doesn't exist in most other languages. Some people consider it a feature of C++, while many considered it one of the quirks/misfeatures of C++.

千寻… 2024-07-14 22:00:08

1. 切片问题的定义

如果 D 是基类 B 的派生类,则可以将 Derived 类型的对象分配给 Base 类型的变量(或参数)。

示例

class Pet
{
 public:
    string name;
};
class Dog : public Pet
{
public:
    string breed;
};

int main()
{   
    Dog dog;
    Pet pet;

    dog.name = "Tommy";
    dog.breed = "Kangal Dog";
    pet = dog;
    cout << pet.breed; //ERROR

尽管允许上述赋值,但分配给变量 pet 的值会丢失其品种字段。 这称为切片问题

2. 如何解决切片问题

为了解决这个问题,我们使用指向动态变量的指针。

示例

Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;         
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed; 

在这种情况下,动态变量的数据成员或成员函数都没有
ptrD(后代类对象)指向的内容将会丢失。 另外,如果需要使用函数,该函数必须是虚函数。

1. THE DEFINITION OF SLICING PROBLEM

If D is a derived class of the base class B, then you can assign an object of type Derived to a variable (or parameter) of type Base.

EXAMPLE

class Pet
{
 public:
    string name;
};
class Dog : public Pet
{
public:
    string breed;
};

int main()
{   
    Dog dog;
    Pet pet;

    dog.name = "Tommy";
    dog.breed = "Kangal Dog";
    pet = dog;
    cout << pet.breed; //ERROR

Although the above assignment is allowed, the value that is assigned to the variable pet loses its breed field. This is called the slicing problem.

2. HOW TO FIX THE SLICING PROBLEM

To defeat the problem, we use pointers to dynamic variables.

EXAMPLE

Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;         
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed; 

In this case, none of the data members or member functions of the dynamic variable
being pointed to by ptrD (descendant class object) will be lost. In addition, if you need to use functions, the function must be a virtual function.

过期以后 2024-07-14 22:00:08

在我看来,除了您自己的类和程序的架构/设计不佳之外,切片并不是什么大问题。

如果我将子类对象作为参数传递给方法,该方法采用超类类型的参数,我当然应该意识到这一点并在内部知道,被调用的方法将仅与超类(也称为基类)对象一起使用。

在我看来,只有不合理的期望,即在请求基类的情况下提供子类,会以某种方式导致子类特定的结果,从而导致切片成为问题。 其要么是该方法的使用设计不佳,要么是子类实现不佳。 我猜测这通常是为了权宜之计或性能提升而牺牲良好的 OOP 设计的结果。

It seems to me, that slicing isn't so much a problem other than when your own classes and program are poorly architected/designed.

If I pass a subclass object in as a parameter to a method, which takes a parameter of type superclass, I should certainly be aware of that and know the internally, the called method will be working with the superclass (aka baseclass) object only.

It seems to me only the unreasonable expectation that providing a subclass where a baseclass is requested, would somehow result in subclass specific results, would cause slicing to be a problem. Its either poor design in the use of the method or a poor subclass implementation. I'm guessing its usually the result of sacrificing good OOP design in favor of expediency or performance gains.

时光是把杀猪刀 2024-07-14 22:00:08

好的,在阅读了许多解释对象切片的帖子后,我会尝试一下,但不知道它是如何成为问题的。

可能导致内存损坏的恶性情况如下:

  • 类在多态基类上提供(意外地,可能是编译器生成的)赋值。
  • 客户端复制并切片派生类的实例。
  • 客户端调用访问切片状态的虚拟成员函数。

OK, I'll give it a try after reading many posts explaining object slicing but not how it becomes problematic.

The vicious scenario that can result in memory corruption is the following:

  • Class provides (accidentally, possibly compiler-generated) assignment on a polymorphic base class.
  • Client copies and slices an instance of a derived class.
  • Client calls a virtual member function that accesses the sliced-off state.
坏尐絯 2024-07-14 22:00:08

切片意味着当子类的对象通过值或从期望基类对象的函数传递或返回时,子类添加的数据将被丢弃。

说明:
考虑以下类声明:

           class baseclass
          {
                 ...
                 baseclass & operator =(const baseclass&);
                 baseclass(const baseclass&);
          }
          void function( )
          {
                baseclass obj1=m;
                obj1=m;
          }

由于基类复制函数不知道有关派生类的任何信息,因此仅复制派生类的基部分。 这通常称为切片。

Slicing means that the data added by a subclass are discarded when an object of the subclass is passed or returned by value or from a function expecting a base class object.

Explanation:
Consider the following class declaration:

           class baseclass
          {
                 ...
                 baseclass & operator =(const baseclass&);
                 baseclass(const baseclass&);
          }
          void function( )
          {
                baseclass obj1=m;
                obj1=m;
          }

As baseclass copy functions don't know anything about the derived only the base part of the derived is copied. This is commonly referred to as slicing.

秋风の叶未落 2024-07-14 22:00:08
class A 
{ 
    int x; 
};  

class B 
{ 
    B( ) : x(1), c('a') { } 
    int x; 
    char c; 
};  

int main( ) 
{ 
    A a; 
    B b; 
    a = b;     // b.c == 'a' is "sliced" off
    return 0; 
}
class A 
{ 
    int x; 
};  

class B 
{ 
    B( ) : x(1), c('a') { } 
    int x; 
    char c; 
};  

int main( ) 
{ 
    A a; 
    B b; 
    a = b;     // b.c == 'a' is "sliced" off
    return 0; 
}
云胡 2024-07-14 22:00:08

当派生类对象分配给基类对象时,派生类对象的附加属性将从基类对象中切掉(丢弃)。

class Base { 
int x;
 };

class Derived : public Base { 
 int z; 
 };

 int main() 
{
Derived d;
Base b = d; // Object Slicing,  z of d is sliced off
}

when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off (discard) form the base class object.

class Base { 
int x;
 };

class Derived : public Base { 
 int z; 
 };

 int main() 
{
Derived d;
Base b = d; // Object Slicing,  z of d is sliced off
}
铃予 2024-07-14 22:00:08

当派生类对象分配给基类对象时,除了基类中不存在的成员外,派生类对象的所有成员都将复制到基类对象。 这些成员被编译器切掉。
这称为对象切片。

这是一个示例:

#include<bits/stdc++.h>
using namespace std;
class Base
{
    public:
        int a;
        int b;
        int c;
        Base()
        {
            a=10;
            b=20;
            c=30;
        }
};
class Derived : public Base
{
    public:
        int d;
        int e;
        Derived()
        {
            d=40;
            e=50;
        }
};
int main()
{
    Derived d;
    cout<<d.a<<"\n";
    cout<<d.b<<"\n";
    cout<<d.c<<"\n";
    cout<<d.d<<"\n";
    cout<<d.e<<"\n";


    Base b = d;
    cout<<b.a<<"\n";
    cout<<b.b<<"\n";
    cout<<b.c<<"\n";
    cout<<b.d<<"\n";
    cout<<b.e<<"\n";
    return 0;
}

它将生成:

[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'

When a Derived class Object is assigned to Base class Object, all the members of derived class object is copied to base class object except the members which are not present in the base class. These members are Sliced away by the compiler.
This is called Object Slicing.

Here is an Example:

#include<bits/stdc++.h>
using namespace std;
class Base
{
    public:
        int a;
        int b;
        int c;
        Base()
        {
            a=10;
            b=20;
            c=30;
        }
};
class Derived : public Base
{
    public:
        int d;
        int e;
        Derived()
        {
            d=40;
            e=50;
        }
};
int main()
{
    Derived d;
    cout<<d.a<<"\n";
    cout<<d.b<<"\n";
    cout<<d.c<<"\n";
    cout<<d.d<<"\n";
    cout<<d.e<<"\n";


    Base b = d;
    cout<<b.a<<"\n";
    cout<<b.b<<"\n";
    cout<<b.c<<"\n";
    cout<<b.d<<"\n";
    cout<<b.e<<"\n";
    return 0;
}

It will generate:

[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文