C++ 理解对象切片

C++ 理解对象切片,c++,C++,为了理解对象切片的问题,我想我已经创建了一个可怕的例子,我正在尝试测试它。然而,这个例子并不像我想象的那么糟糕 下面是一个简单的工作示例,如果您能帮助我理解为什么它仍然“正常工作”,我将不胜感激。如果你帮我把这个例子弄得更糟,那就更好了 #包括 #包括 模板类基{ 受保护的: std::函数f;//继承 公众: Base():f{[](){返回T{0};}}}{}//已初始化 虚T func1()常量{return f();} virtual~Base()=default;//避免子级内存泄漏

为了理解对象切片的问题,我想我已经创建了一个可怕的例子,我正在尝试测试它。然而,这个例子并不像我想象的那么糟糕

下面是一个简单的工作示例,如果您能帮助我理解为什么它仍然“正常工作”,我将不胜感激。如果你帮我把这个例子弄得更糟,那就更好了

#包括
#包括
模板类基{
受保护的:
std::函数f;//继承
公众:
Base():f{[](){返回T{0};}}}{}//已初始化
虚T func1()常量{return f();}
virtual~Base()=default;//避免子级内存泄漏
};
模板类子类:公共基{
私人:
T值;
公众:
Child():Child(T{0}{}
Child(const T&val):Base{},val{val}{//初始化Base::f
Base::f=[&](){返回此->val;};//复制分配Base::f
}
T func1()常量重写{返回T{2}*Base::f();}
void setval(const T&val){this->val=val;}
};
模板T间接(常量基b){返回b.func1();}
int main(int argc,char*argv[]){
碱基b;
儿童{5};

std::cout当前代码中没有未定义的行为。但是,使用它很危险,因此很容易做出未定义的行为

切片发生了,但是您访问
this->val
。这看起来很神奇,但您只是从主目录中的
Child c
访问
this->val

这是因为lambda捕获。您捕获
this
,它指向main中的
c
变量。然后将该lambda分配到基类内的
std::function
。基类现在有一个指向
c
变量的指针,以及通过
std::fu访问
val
的方法操作

因此,发生了切片,但您可以访问未切片的对象

这也是数字不乘以2的原因。虚拟调用解析为base,main中
c
val
的值为
10

您的代码大致相当于:

struct B;

struct A {
    B* b = nullptr;

    int func1() const;
};

struct B : A {
    int val;
    explicit B(int v) : A{this}, val{v} {}
};

int A::func1() const {
    return b->val;
}

int main() {
    B b{10};

    A a = b;

    std::cout << a.func1() << std::endl;
}
structb;
结构A{
B*B=nullptr;
int func1()常量;
};
结构B:A{
int-val;
显式B(intv):A{this},val{v}{
};
int A::func1()常量{
返回b->val;
}
int main(){
B{10};
A=b;

std::cout“和f现在很容易出现未定义的行为”,在我的示例中,
f
似乎也能正常工作未定义的行为是未定义的。未定义行为的许多可能表现形式之一是代码似乎工作正常。@AlgirdasPreidžius,在我的示例中,上面的行为也是未定义的吗?在这个有限、最简单的示例中,我只是因为运气或一些变量缓存而获得似乎工作的代码吗?这就是我想要的理解。我不知道,你的例子中的代码是否产生了未定义的行为。我只是想声明,代码似乎工作正常这一事实并不能证明它没有表现出未定义的行为。@ArdaAytekin你在lambda中通过引用捕获。lambda的目的是什么?通过引用捕获lambda并在我看来,复制是一个更加隐蔽的错误。
Child d=c;c.setval(55);std::cout@ArdaAytekin我有一个答案给你。你的代码很危险,但没有未定义的行为。一旦这个问题被重新打开,我将在回答中解释。感谢你们两人友好地回答,而不是简单地声称这篇文章是重复的,并且在你的解释中是非常有教育意义的。现在我也可以看到如何在这段代码中可能会发生危险的事情,特别是当
B
(或者,
子代码
)实例离开了作用域,
Child
Base
部分中的
this
无效。这可能是中的行为,我一开始就试图理解。你也可以详细说明一下按值捕获吗?我没想到我正在捕获
this
,只是
this->val
@ArdaAytekin如果你有c++14,你可以这样捕获:
val=this->val
。它将按值捕获
val
。请注意,如果
Child
中的值发生变化,lambda中的值将不会更新。为什么我需要c++14呢?我的意思是,c++11中不支持按值捕获吗?我需要哪种特定功能n C++11启用了这种行为?@ArdaAytekin它是受支持的,但在成员的情况下更难实现。要捕获成员,lambda必须捕获
,但
是指针!因此,要在C++11中通过值捕获成员,必须创建一个与成员相等的局部变量并捕获该局部变量。C++14 sim通过允许捕获后的
=value
设置自定义值来执行此过程。@ArdaAytekin在
struct B;

struct A {
    B* b = nullptr;

    int func1() const;
};

struct B : A {
    int val;
    explicit B(int v) : A{this}, val{v} {}
};

int A::func1() const {
    return b->val;
}

int main() {
    B b{10};

    A a = b;

    std::cout << a.func1() << std::endl;
}