分类: C/C++
2013-09-24 13:46:17
原文地址:容易犯错的c++小细节(1) 作者:风箫夜吟
(1)运行下图中的C++代码,输出是什么?
int SizeOf(char pString[])
{
return sizeof(pString);
}
int main(int argc, char* argv[])
{
char* pString1 = "google";
int size1 = sizeof(pString1);
int size2 = sizeof(*pString1);
char pString2[100] = "google";
int size3 = sizeof(pString2);
int size4 = SizeOf(pString2);
printf("%d, %d, %d, %d \n", size1, size2, size3, size4);
return 0;
}
答案:4,
1, 100, 4。pString1是一个指针。在32位机器上,任意指针都占4个字节的空间。*pString1是字符串pString1的第一个字符。一个字符占一个字节。pString2是一个数组,sizeof(pString2)是求数组的大小。这个数组包含100个字符,因此大小是100个字节。而在函数SizeOf中,虽然传入的参数是一个字符数组,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。
(2)
#include
using namespace std;
class A
{
public:
A()
{ std::cout << "A is created." << std::endl; }
~A()
{ std::cout << "A is deleted." << std::endl; }
};
class B : public A
{
public:
B()
{ std::cout << "B is created." << std::endl; }
~B()
{ std::cout << "B is deleted." << std::endl; }
};
int main(int argc, char* argv[])
{
A* pA = new B();
delete pA;
return 0;
}
答案:输出三行,分别是:A is created. B is created. A is deleted。用new创建B时,回调用B的构造函数。在调用B的构造函数的时候,会先调用A的构造函数。因此先输出A is created. B is created.
接下来运行delete语句时,会调用析构函数。由于pA被声明成类型A的指针,同时基类A的析构函数没有标上virtual,因此只有A的析构函数被调用到,而不会调用B的析构函数。
由于pA实际上是指向一个B的实例的指针,但在析构的时候只调用了基类A的析构函数,却没有调用B的析构函数。这就是一个问题。如果在类型B中创建了一些资源,比如文件句柄、内存等,在这种情况下都得不到释放,从而导致资源泄漏。
(3)
#include
#include
using namespace std;
struct Point3D
{
int x;
int y;
int z;
};
int main(int argc, char* argv[])
{
Point3D* pPoint = NULL;
int offset = (int)(&(pPoint->z));
printf("%d\n", offset);
return 0;
}
输出8。由于在pPoint->z的前面加上了取地址符号,运行到此时的时候,会在pPoint的指针地址上加z在类型Point3D中的偏移量8。由于pPoint的地址是0,因此最终offset的值是8。
&(pPoint->z)的语意是求pPoint中变量z的地址(pPoint的地址0加z的偏移量8),并不需要访问pPoint指向的内存。只要不访问非法的内存,程序就不会出错。
(4)class A
{
private:
int m_value;
public:
A(int value)
{
m_value = value;
}
void Print1()
{
printf("hello world");
}
void Print2()
{
printf("%d", m_value);
}
};
int main(int argc, char* argv[])
{
A* pA = NULL;
pA->Print1();
pA->Print2();
return 0;
}
分析:答案是Print1调用正常,打印出hello
world,但运行至Print2时,程序崩溃。调用Print1时,并不需要pA的地址,因为Print1的函数地址是固定的。编译器会给Print1传入一个this指针,该指针为NULL,但在Print1中该this指针并没有用到。只要程序运行时没有访问不该访问的内存就不会出错,因此运行正常。在运行print2时,需要this指针才能得到m_value的值。由于此时this指针为NULL,因此程序崩溃了。
(5)
分析:答案是不可以。C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const
this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时static的用法和static是冲突的。
分析:答案是不能。调用静态成员函数不要实例。但调用虚函数需要从一个实例中指向虚函数表的指针以得到函数的地址,因此调用虚函数需要一个实例。两者相互矛盾。
(6)
C++中静态成员函数能不能同时也是虚函数?