所以,我认为我已经足够开始尝试一些框架/ apis,所以我正在考虑学习qt框架,以便我可以开始开发一些简单的gui应用程序,
无论如何,我注意到qt MainWindow.cpp文件中有一个奇怪的东西
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
所以我理解ui是一个指针,我们将一个新的MainWindow对象分配给该指针
但是每当程序崩溃时我用自己的代码做同样的事情
#include <iostream>
using namespace std;
class Sample{
public:
Sample* ss; [c++]
string text = "hey ya";
explicit Sample()
:ss(new Sample){
cout << "hi" << endl; // doesn't print hi?
}
void print(){
cout << ss->text << endl;
}
~Sample(){
delete ss;
}
};
int main()
{
cout << "Hello world!" << endl;
Sample s;
return 0;
}
起初我认为崩溃是因为无限递归,每个构造函数将继续调用一个新的样本
但是如果是这样的话,不应该打印到控制台吗?
为什么这个代码在qt中有效,但是我的工作还没有成功,我的意思是它做了同样的事情,
请注意,在qt MainWindow标头中,构造函数是标记显式的,如果这有任何区别,我尝试将我的Sample类中的构造函数标记为显式,但仍然崩溃
感谢
答案 0 :(得分:4)
但是每当我用自己的代码做同样的事情时 程序崩溃
它不是“几乎相同” - 在外观上 - 有些,但是当你不注意细节时看起来可能是欺骗,但在功能上它远非如此。
您的代码是一个无限创建自己的类,该类的每个新实例都创建另一个实例,该实例创建另一个实例,依此类推,直到您遇到某些(运行时,操作系统或硬件)限制并且您的应用程序崩溃。即使是第一个创建的对象,您的代码也永远不会到达“hi”部分。
这与Qt示例代码无关。在该代码中,类不会在构造函数中创建自身的新实例。它创建了一个从UI表单生成的不同类。虽然类名相同,但不是同一个类,因为它存在于Ui
命名空间中。这些类名称相同,因为它们是互补的,它们不一定是,但这就是Qt在为您生成代码时所做的事情。这是有道理的,因为它清楚地表明哪个窗口小部件类对应于哪个窗体类。
MainWindow
和Ui::MainWindow
不是相同的类,这就是为什么它有意义并且确实有效。
请注意,C ++甚至不会让你在同一个类中有一个类的实例,既不是直接也不是通过间接继承或聚合,这是默认的no-no,因为无限递归对于编译器来说是显而易见的,无论多么深刻它可能是嵌套的。但是有一个指针是可以的,因为指针基本上只是对另一个可以经常使用的对象的引用,你必须承担责任,即使它创建了另一个相同类型的对象,而不是简单地引用一个预先存在的对象,您可以限制该行为,使其不会遇到无限递归。
struct RTest {
RTest(int & d) {
qDebug() << "hi" << d;
t = d++ < 10 ? new RTest(d) : nullptr;
}
RTest * t;
};
在这种情况下,递归限制为10的深度。请注意,如果在初始化列表中执行指针初始化,则不会从0到10获得hi
,而只会{{1}在递归完成之前,将无法访问第一个对象的构造函数的主体,这就是为什么你永远不会将代码传递给hi 11
。
答案 1 :(得分:1)
但如果是这样的话,不应该打印到控制台吗?
不。构造类时,首先会发生类成员初始化列表。这意味着
ss(new Sample)
在您进入构造函数体之前发生。由于该行创建了一个新的Sample
,您初始化Sample
,这将创建另一个新的Sample
,此过程将永久发生,直到操作系统停止或进程崩溃