我有以下代码(关于 main.cpp 中的索引有错误):
#ifndef SAMPLE_HPP
# define SAMPLE_HPP
# include <iostream>
# include <string>
class Sample{
public:
Sample(void);
~Sample(void);
void tellname(void) const;
private:
std::string _name;
};
#endif
#include <iostream>
#include "Sample.hpp"
Sample::Sample(void){
this->_name = "testname";
return;
};
Sample::~Sample(void){
return;
}
void Sample::tellname(void) const{
std::cout << "Name : " << this->_name << std::endl;
return;
}
#include "Sample.hpp"
int main(void){
int i;
Sample *test;
test = new Sample[4];
i = 0;
while (i++ < 4) // I know : i++; shouldn't be here
test[i].tellname();
delete [] test;
return 0;
}
如果我编译它,我得到以下输出:
Name : testname
Name : testname
Name : testname
Name :
关于最后一行,它会调用一个方法(void Sample::tellname(void)
),但是来自不在表格范围内的实例(test[4]
没有&#t; t存在)。
但是,它仍会调用tellname()
,即使它所称的实例也不存在。它只是认为其_name
字段为空。
这怎么可能?
答案 0 :(得分:5)
这只是未定义的行为,C ++没有任何要求,因此“任何事情都可能发生”。你所看到的只是一个巧合,毫无价值的理由:下次你运行它可能会崩溃,显示nyan cat等等。
答案 1 :(得分:3)
i
从1到4包含,因为tellname
是const,test[4].tellname()
是Sample::tellname
,Sample
是未定义的结构,因此“名称:”是正确打印的,然后打印test[4]._name
中的内存,幸运的是test[4]._name*
指向的内存非空,甚至是结束字符串char。
所以,你很幸运。
答案 2 :(得分:3)
听起来你在想为什么要调用这个函数。在内存中,结构不包含其中的函数。相反,函数的一个副本放在可执行文件的某个位置。因此,当您致电test[4].tellname()
时,实际发生的事情是:地址test + (4 * sizeof(Sample))
将传递给函数tellname()
。该地址的值未定义。
这是一个让您了解正在发生的事情的示例:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
struct bstruct {
int y = 100;
};
int main()
{
bstruct b;
((astruct*)&b)->prnt();
getchar();
return 0;
}
这里prnt()
幕后传递bstruct的地址并将其视为astruct的地址,因为bstruct中的第一个值是100,它打印100.你甚至可以将它简化为:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
int y = 100;
int main()
{
((astruct*)&y)->prnt();
getchar();
return 0;
}