C++类的静态函数是属于类型的,而不是某个对象的,因此把它声明成Virtual也没什么实际意义。那么运行下面这段程序,会产生什么样的结果呢?
1 2 3 4 5 6 7 8 | #include <iostream> using namespace std; class Base { public: static void foo() { cout<<"Base"<<endl; } virtual void bar() { foo(); } }; |
C++类的静态函数是属于类型的,而不是某个对象的,因此把它声明成Virtual也没什么实际意义。那么运行下面这段程序,会产生什么样的结果呢?
1 2 3 4 5 6 7 8 | #include <iostream> using namespace std; class Base { public: static void foo() { cout<<"Base"<<endl; } virtual void bar() { foo(); } }; |
想一下,下面的代码片段会输出什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <iostream> class Test { public: void print() const { std::cout<<_int<<std::endl; } private: static int _int; }; int Test::_int = 0; int main(int argc, char **argv) { Test TArray[10]; TArray[100].print(); return 0; } |
May you note something, anyhow.
1 2 3 4 5 6 7 8 9 10 11 12 13 | void fun1(char * str) {} void fun2(char ** str) {} //~ int main(int argc, char ** argv) int main(int argc, char * argv[]) { char str1[] = "Hello, Piggy!"; char str2[][4] = "Hello, Piggy!"; fun1(str1); fun2(str2); fun2(&str1); return 0; } |
上面的snippet有错误吗?有几个?你能找出来并说出原因吗?4、5两行有区别吗?想一下,然后看gcc给出的错误信息,
1 2 3 4 5 6 7 | int main() { char * str = new char[32]; str = "Hello, Piggy!"; return 0; } |
这样是会内存泄漏的……而我一直都不知道……不过想来也自然,因为这样是允许的,char *str = “Hello, Piggy!”;,“程序中的字符串被存放在常量存储区”不要把这句话当成耳旁风,谨记。
看Chris对内联的总结,说到内联函数在编译时会被放入”符号表”,想一探究竟,结果却发现另外一个问题,疑惑不解。
1 2 3 4 5 6 7 | #include <stdio.h> inline int add(int a, int b) { return a + b; } int main() { int n = add(1,2); return 0; } |
就在刚刚过去的2009年11月11日,举国欢庆的光棍节,Google推出了一个全新的系统编程语言Go Program Language. ……Simple……Fast……Safe……Concurrent……Funny……Open Source……似乎很牛B的样子,观望……期待……祝福
这里,编译main.cpp生成main.o时发现无法找到f到定义,就把它当作外部符号填入外部符号表,等待链接时确定其地址。而f(1); f(10); 通常是对应两条jmp 0x****h指令(当然还有参数的压栈操作),0x****h地址处通常就是一条call f; (C++还会对f进行mangling处理)。这样链接器在链接main.o和test.o时,从test.o到导出符号表(或者内部符号表?)中找到f,得到对应的地址(每个符号对应一个偏移地址),用这个地址替换f,再进行其他的一些必要的重定位,一个可执行文件就形成了。
说了这么多,那么C++模板为什么不能分离式编译呢?
有的东西,你自己觉得自己理解了知道了记住了,可能你真的记住了,但你真的理解了吗?Put a “Why” upon everything ever you touch.
sizeof仅仅是个运算符,但那又意味着什么呢?意味着它不是一个函数,意味着它是在编译期求值(我并不是说所有的运算符都编译期求值)的。对于这样一条语句:
1 | size_t size = sizeof(int); |
来说,仅仅对应着这样一条汇编指令:
1 | movl $4, -4(%ebp) |
这对于自定义类型class也是同样的。
这里面猫腻儿还真不少。
karmic到源里面没有以前到vim-full包了,取而代之到是vim包,但现在有很多问题,n”+yy和n”+p无法和系统”剪切板”里到内容关联了,不知道什么原因。
Update
一切都释然了,只要意识到,>也需要进行类型提升。那么后面到-1啦-2啦之类的,都是很大很大的数了,循环根本就进不去,更别提死循环了。这样看来四、五两段程序就没有必要列出来了。其实,我是被它们的汇编代码给迷惑住了。
只占了十分之一左右!这又是为什么呢?永远也学不完的虚拟内存啊!
呃……又SB了!const int size = 2^30;这哪里是1G啊!分明是28嘛!Orz…汇编码里面尽是28!这下好了,改成1<<30,运行了四个实例,机器就笨的像猪了:
等程序结束了,刚开始运行着到浏览器也慢了一会儿,估计是被换到交换文件里面去了。