提问人:Cherry Toska 提问时间:5/9/2020 最后编辑:Cherry Toska 更新时间:5/10/2020 访问量:115
子类的动态方法在 lambda 捕获中使用时调用父类的虚拟方法/导致 segmentatin 错误
Child class' dynamic method calls parent class' virtual method when used in lambda capture / results in segmentatin fault
问:
编辑:在虚拟函数的实现中使用 final 关键字会导致打印正确的字符串,但为什么这里需要 final 关键字?有人可以解释一下吗?
我正在修补可变参数模板,我有非常通用的类 D1、D2、D3 ......它们都来自A类。每个类都有静态和动态打印功能,父类具有用于动态调度的虚拟动态打印功能。当我尝试在单个文件上重现它时:
class A {
public:
virtual void printDynamic();
static void printStatic();
}
class D1 : public A {
public:
virtual void printDynamic();
static void printStatic();
}
我有以下变体:
std::variant<A,As...> apvar;
std::variant<A*,As*...> avar;
我使用所有派生类 D1、D2 实例化了这两个变体,...(我知道向上投射指针,我只想取消引用它们的类型并做随机的事情)
我已经为包装器实现了递归访问者,我需要捕获这一点,因为我将大部分函数封装在一个类中,当我在类上调用访问者时,我得到的名称是“DX”、“DX”;X 对应于 1。
template<class X, class Y, class... Zs>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
value.printStaticName();
value.printDynamicName();
} else{
visit_actor<Y,Zs...>();
}
}, avar
);
}
但是,如果我在指针变体上调用访问者,并且当我调用函数时: 对于静态函数,我得到:“DX”,X 对应于 I,但是当我调用动态函数时,我得到的名称是:“抽象 A”。
template<class X, class Y, class... Zs>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
value->printStaticName();
value->printDynamicName();
} else{
visit_pointer<Y,Zs...>();
}
}, apvar
);
}
我尝试在 c++ 文档中阅读它,但还找不到原因。派生类的静态函数被调用,而父级虚函数被调用的原因是什么?
对于最小可生产示例,您需要实例化类:
#include <variant>
#include <iostream>
#include <string>
template <class T>
using expr_type = std::remove_cv_t<std::remove_reference_t<T>>;
template<class A,class... As>
class ActorWrapper{
public:
std::variant<A,As...> var;
template<class Ins>
ActorWrapper(Ins ins) : var(ins) {}
};
template<class A,class... As>
class ActorPointer{
public:
std::variant<A,As... > var;
template<class T>
ActorPointer(T* t) : var(t) {}
};
class X {
public:
int a;
virtual std::string getDynamicName() {
return "dynamic X";
}
static std::string getStaticName(){
return "static X";
}
};
class D1 : public X{
public:
bool b;
std::string getDynamicName() override {
return "dynamic D1";
}
static std::string getStaticName(){
return "static D1";
}
};
class D2: public X {
public:
bool b;
std::string getDynamicName() override {
return "dynamic D2";
}
static std::string getStaticName(){
return "static D2";
}
};
template<class A, class... As>
class TemplatedAGraph{
private:
//change aw to correspond to ap
template<class X>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "z" << std::endl;
std::cout << value.getStaticName() << std::endl;
std::cout << value.getDynamicName() << std::endl;
}else{
std::cout << "d" << std::endl;
return;
}
}, aw.var
);
}
template<class X, class Y, class... Zs>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "x" << std::endl;
std::cout << value.getStaticName() << std::endl;
//std::cout << value.getDynamicName() << std::endl;
} else{
std::cout << "y" << std::endl;
visit_actor<Y,Zs...>();
}
}, aw.var
);
}
template<class X>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "a" << std::endl;
std::cout << value->getStaticName() << std::endl;
std::cout << value->getDynamicName() << std::endl;
}else{
std::cout << "b" << std::endl;
return;
}
}, ap.var
);
}
template<class X, class Y, class... Zs>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "c" << std::endl;
std::cout << value->getStaticName() << std::endl;
std::cout << value->getDynamicName() <<std::endl;
} else{
//std::cout << typeid(decltype(value)).name() <<std::endl;
//std::cout << typeid(X).name() <<std::endl;
//std::cout << std::is_same_v<decltype(value),X> << std::endl;
std::cout << "d" << std::endl;
visit_pointer<Y,Zs...>();
}
}, ap.var
);
}
public:
ActorPointer<A*,As*...> ap;
ActorWrapper<A,As...> aw;
void print_names(){
visit_actor<A,As...>();
}
void print_names_w_pointer(){
visit_pointer<A*,As*...>();
}
//change ap to coresspond to aw
template<class X>
TemplatedAGraph(X a) : ap(&a), aw(a) {}
};
int main(){
D2 d2;
D2* d2ref = &d2;
std::cout << d2ref->getDynamicName() << std::endl;
TemplatedAGraph<D1,D2> tag(d2);
tag.print_names();
tag.print_names_w_pointer();
}
输出为:
thrud@thrud ~/wörk/test $ g++ main.cpp -std=c++17
thrud@thrud ~/wörk/test $ ./a.out
dynamic D2
y
z
static D2
dynamic D2
d
a
static D2
Segmentation fault
所以我想我偶然发现了一个未定义的行为,但我仍然想知道原因。
答:
2赞
Igor Tandetnik
5/9/2020
#1
TemplatedAGraph(X a) : ap(&a), aw(a) {}
将指向局部变量的指针存储在 中。不久之后,该指针就变得悬而未决。然后,任何访问它的尝试都会表现出未定义的行为。ap
你可能的意思是.这样,据我所知,您的代码可以正常工作。TemplatedAGraph(X& a) :...
评论