为啥我不能在主函数之外定义一个类的对象(继承了另一个类)?
Posted
技术标签:
【中文标题】为啥我不能在主函数之外定义一个类的对象(继承了另一个类)?【英文标题】:Why can't I define a object of class(which inherited another class) outside the main function?为什么我不能在主函数之外定义一个类的对象(继承了另一个类)? 【发布时间】:2020-06-27 12:15:29 【问题描述】:我目前正在使用 fltk 库处理 VS15。当我尝试在主函数之外创建我的类的对象(继承 Fl_Double_Window)时,程序崩溃了。
#include"FL/Fl.H"
#include"FL/Fl_Double_Window.h"
#include"FL/Fl_draw.h"
#include"FL/Fl_Slider.H"
#include"FL/Fl_Input.H"
#include"FL/Fl_Button.H"
#include"FL/Fl_Text_Display.H"
#include<string>
struct MyWindow :Fl_Double_Window
MyWindow(string s):Fl_Double_Window(10, 10, 500, 500, s.c_str())
color(FL_BLACK);
show();
;
MyWindow window("Special");
int main()
return Fl::run();
但是,当我直接创建 Fl_Double_Window 类的对象时,一切正常(同样在主函数之外):
#include"FL/Fl.H"
#include"FL/Fl_Double_Window.h"
#include"FL/Fl_draw.h"
#include"FL/Fl_Slider.H"
#include"FL/Fl_Input.H"
#include"FL/Fl_Button.H"
#include"FL/Fl_Text_Display.H"
#include<string>
string name = "Special";
Fl_Double_Window window(10, 10, 500, 500, name.c_str());
int main()
window.color(FL_BLACK);
window.show();
return Fl::run();
我下载代码的那个人使用 C++11 在 Ubuntu 上运行代码,该程序在这两种情况下都有效。 我很困惑,我真的无法弄清楚问题所在。
【问题讨论】:
一个临时的字符指针,听起来像 UB(未定义的行为) 如果你不明白 @JVApen 在MyWindow(string s):Fl_Double_Window(10, 10, 500, 500, s.c_str())...
中谈论 s.c_str()
因为根据定义 s 是暂时的所以你不能假设它的内部持续时间c_str()
返回的指针
你为什么在 Fl_Double_Window 中使用char*
而不是string
?
@bruno 我不知道,这正是 FLTK 库的创建者决定的。
@Xeron 如果您不能使用文字字符串代替 std::string
来命名您的窗口,则重复 c_str()
的结果,例如strdup(xxx.c_str())
... 即使是 lib 获取指针为 const
所以永远不会释放它,很遗憾有一个使用 char *
的 C++ lib ...
【参考方案1】:
您正在崩溃,因为您在构造函数中放置了 show(如 @bruno 所述)。如果您从构造函数中取出 show 并将其放入 main 中,您将不会看到您看到的崩溃,但由于@Sam Varshavchik 提到的原因,标题将不正确。
struct MyWindow :Fl_Double_Window
MyWindow(const std::string& s)
: Fl_Double_Window(10, 10, 500, 500) // 1) Do not set the title here
, caption(s) // 2) Take a copy of the title
// 3) Set the title here
this->copy_label(caption.c_str());
color(FL_BLACK);
// 4) Remove show from constructor
// show();
// 5) Declare caption - see Sam's solution
std::string caption;
;
MyWindow window("Special");
int main()
// 6) Move show here
window.show();
return Fl::run();
【讨论】:
我在 6 月 27 日对 OP 问题的评论中说,但 OP 没有反应。 我只是看到了 - 没有在其他 cmets 上展开。【参考方案2】:MyWindow(string s)
构造函数与函数没有太大区别。 s
是构造函数的参数。一旦构造函数返回,s
就会被销毁。
:Fl_Double_Window(10, 10, 500, 500, s.c_str())
c_str()
返回一个指向s
内容的指针,并将它传递给超类的构造函数。然而,因为s
将被破坏,对该指针的任何进一步使用都将成为未定义的行为,并且可能会崩溃。这显然是正在发生的事情。
解决方案有点复杂。如果您仍然希望从FL_Double_Window
继承,这需要一个微妙的杂耍行为:
struct my_data
string s_name;
my_data(string s) : s_name(s)
;
struct MyWindow :my_data, Fl_Double_Window
MyWindow(string s): my_data(s),
Fl_Double_Window(10, 10, 500, 500, this->s_name.c_str())
color(FL_BLACK);
show();
;
这会调整事物的构造和销毁顺序,因此只要 FL_DoubleWindow 存在,s_name
类成员就会继续存在。
还有一个(更)更简单的传递引用的选项,但是只要窗口对象存在,您就必须确保引用的std::string
存在。这种方法虽然有点麻烦,但也更防弹。
【讨论】:
感谢您的回答,但程序继续崩溃... 您的调试器显示崩溃的原因是什么? First_example.exe 中 0x777029CC (ole32.dll) 处未处理的异常:0xC0000005:访问冲突读取位置 0x00000004。 您的调试器显示的信息远不止这些。例如,调试器显示每个堆栈帧中所有变量的值,并让您确定崩溃的确切原因。当我编译并链接我的版本时(在添加了您必须拥有的缺少的using namespace std
之后),程序运行没有问题,并打开一个黑色窗口。您的崩溃一定是因为其他一些代码,而不是这个。您应该花一些时间学习如何使用调试器。这就是调试器的用途。了解如何使用调试器是每个 C++ 开发人员必备的技能。
是的,我只是从 Stroustrup 的《使用 C++ 的原则和实践》一书中学习 C++,所以我还没有接触到调试器。你确定你在主函数之外定义了一个 MyWindow 对象,因为当我在主函数内定义一个 MyWindow 对象时,即使程序也适用于我?以上是关于为啥我不能在主函数之外定义一个类的对象(继承了另一个类)?的主要内容,如果未能解决你的问题,请参考以下文章