C++中,出了基本类型以外,就是类类型。对一个类类型的实例,均叫做一个对象。实际上C++上面,只要是一个变量都可以称作对象。
但这里狗屎的问题就有了。对象的类型是有可能存在继承关系的。
以前在C语言里面,可以有这样的变量转换。
int a = 1000;
long b = 0;
b = (long)a; //这里做了强制转换
但如果在C++里面还是用C风格方式的类型转换就会存在很严重的问题。例如有这么一段代码
class IInterface_Me
{
protected:
int a;
}
class CInterface_1 : public IInterface_Me
{
public:
int b;
}
class CInterface_2 : public IInterface_Me
{
public:
int c;
}
IInterface_Me* pInterface = new CInterface_1;
CInterface_2* pInterface_2 = (CInterface_1*)pInterface;
pInterface_2->b = 100; ///这里就要出错。
对于这个问题主要原因是由于c语言风格的类型强转,主要是由于编译器不做检查,因此在C++里面应该使用安全的类型转换修饰符(static_cast之类)。
回家过年半个月了,现已经回杭州。在家里的这段时间,家里都在人劝我回家工作生活,其实我自己也非常矛盾。
外面有外面的诱惑和痛苦,家里有家里的清闲和无聊。
回到家里,有一大帮人在一起热热闹闹。尽管偶尔有矛盾,但始终是一个大家庭,再苦再难也能一同度过。在家至少不用考虑养老等等乱七八糟的生活温饱类问题,但信息的及时性和收入很是一个头疼问题。
出门在外,靠的都是看不见的东西和看得见的东西。 不过,只要不是太复杂的地方,大家都回按规矩来。在外面,只要努力或者机遇不错的话,物质不会太容易成为问题,唯独存在的问题就是养老、房子这些长远的问题。
这次回家时间相对长一些,感受不同。加上这次的一些经历,对一些问题有了不同的认识和看法。我也在想是不是就一定非要在外面?
虽然仅仅几个小时的,我就从过着春天的地方进入了过着冬天的地方。
但年纪越大对待这些问题越来越迷茫,说实话,出门在外举目无亲,相比那点比家里高一些的收入的来说,其他真的没有多少优势。要说机会优势,公平优势。现在对我来说还真的越看越淡。
家里气候不错,生活确实无忧无虑,加上将近二十年的生活过来,情感上多少有点舍不得。老爹老妈年纪大了,有些事情和东西逐渐有所认识。随着阅历和年纪的增长,矛盾的东西越来越多了。
生活不可能每天都过着旅游般的生活,但我始终向往这样的生活;要怎么样就这么样,来去自由。
对于我这样的人来说,想要自由,就要失去丰富的物质基础。想要丰富的物质基础就要放弃自由,进入鸟笼般的生活,成为社会前进的一颗机械式齿轮。
围城!城外不懂城内人的苦,城内人不懂城外的憧憬。大家往往容易被一些简单的表面现象蒙蔽了眼睛,有时候我试图权衡并做出选择。但说实话,这次真的难住我了。接下来只能在以后的成长路上继续寻找答案,或者等待某朝当局改变这种人吃人的局势?
最近要开始搞P2P+NAT穿越。实际上就是一个p2p+nat打洞而已。
因为以前搞过路由器的东西,所以理解nat就很简单。说到底就是个会话表和会话项的问题。我在看老外的一个RFC草稿文档,看得晕乎要死。
老外把各种类型的NAT抽象成住户邀请其他住户的问题,这个看起来不但麻烦,而且不直观。不过也是因为做过路由交换的人来说,因为有基础,所以看起来很轻松,相反看着文档很头疼。
1,数据结构回顾,找本靠谱的,然后实现一把例子啥的。
2,高数回顾,公式跟着推导一把
3,找本能看懂的离散书,主要看公式推导这块
4,1、2和3都已经ok了以后,看算法导论。
折半查找的前提是,数列需要是有序的。
有这么一个数组:【10, 11, 100, 200, 232, 245, 246, 400】
需要进行查找 10 这个元素
最近在学opengl,在看一个例子中。opengl的只有60fps,感觉到很好奇。
无意见发现显示器的刷新速度也是60hz。修改了显示器的刷新速度为75hz以后,opengl渲染的那个范例也提高到了75fps。
可见opengl默认情况下最大刷新速度与当前屏幕的刷新速度一致。
也就是说,如果运行一个非全屏游戏时,设定的设定的刷新速度为60hz,那么整个游戏的最大fps就为60hz。
得到的结论:最大刷新速度不超过当前显示屏幕设定的设定刷新速度。不知道对于全屏游戏来说是怎样的?
我们公司有这个一段代码,后来看了高效c++之后就总感觉有问题。不试不知道,一试全是地雷阵。
一般会写这么一个函数,返回的是引用。这样也符合C++里面的一些思想。但如果这样的函数没有用好的话,留下的就是一个地雷
std::vector<int>& Return_null_reference()
{
.....
}
例如有如下代码
std::vector<int>& Return_null_reference()
{
std::vector<int> *pTmp = NULL;
return *pTmp;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
std::vector<int> *pTmp1 = NULL;
pTmp1 = &Return_null_reference();
std::vector<int> &pTmp2 = Return_null_reference();
Sleep(1);
}
我在vs 2008 sp1中编译不但能够通过,而且不会报错。执行的结果就是,ptmp1指向了一个空指针,ptmp2引用了一个空指针。
这里实际上看上去ptmp2会有问题,因为在引用的变量定义时,需要在编译器就要确定引用的对象是一个非NULL地址。但事实上这里因为引用了一个函数的返回,由于函数的返回值是属于运行时问题,所以编译器不做检查。于是就留下了一个坑。
高效C++中说过,不要随便引用一个指针指向的对象,因为有可能那个指针是指向NULL。
同时也隐约讲过引用不的不当反而比指针会更危险。
要利用编译器检查引用非NULL的特性,需要显示的指明被引用的对象是编译时就可以确定内存地址的。
class A
{
public:
…
}
一般对于使用者来说这个类只有1个数据结构,那就是类本身。
实际上,一个类包含了3个数据结构。
除了类本身以外,还包含了一个函数表、和指向函数表的指针。
函数表是用来保存虚函数在本类中的中的具体实现地址的。
而指向函数表的指针,值用于表示某个虚函数在函数表的地址。
之前简单看过一点c++11的特性,里面讲了一堆左值和右值。说来说去有一部分还是在谈论关于临时变量的问题。
目前有这么一个函数:
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
Rational result(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
return result;
}
上面这个函数在调用的时候因为返回的是局部变量,因此返回的时候编译器会插入代码会产生一个临时变量,然后将result拷贝到临时变量中返回出去。但让这里谈论的前提是,一些编译器的优化关掉。
而对于下面的代码来说编译器的行为就会不一样。因为这段代码已经显式的告诉编译器,这个这里会构建一个匿名的临时变量并返回,因此编译器在这里不会再次构建临时变量,而是直接将代码中创建的匿名对象直接返回出去给外面。这样做可以节约一个对象的创建和销毁时间复杂度。
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
在调用函数时,一般都不建议采用值传递,原因是因为要建立一个临时的拷贝;这样会带来空间和时间复杂度的提升。
一般除非很特殊情况,很少把对象以值的方式进行传递到函数里面。
实际上,不讲对象做值传递还有一个比较重要的原因。
在C++的多态中,如果父类的指针指向了一个子类对象,并对该对象做值传递,会导致子类数据丢失。大致代码如下:
class CA
{
};
class CB : public CA
{
};
void func(CA src);
int main()
{
CA* p1 = new CB;
func(*p1);
....
}
在这个代码里,实际上调用func时,使用了CA的默认拷贝构造函数,因为对于CB的所有数据就丢失了,在func里面的临时对象也仅仅是CA类型。
首先说一下++重载符,++分为前后两种方式的调用。因此就有了两种的符号的调用。大致如下(对于后置++的做法采用了不严谨的重载,返回的应该是 const对象)
namespace class_cplusplus10
{
class CBase
{
public:
CBase& operator++() //这里是前置++调用
{
printf(_T("class_cplusplus10::CBase& operator++()\n"));
return *this;
}
CBase& operator++(int) //这里是后置++调用
{
printf(_T("class_cplusplus10::CBase& operator++(int)\n"));
return *this;
}
CBase& operator--()
{
printf(_T("class_cplusplus10::CBase& operator--()\n"));
return *this;
}
CBase& operator--(int)
{
printf(_T("class_cplusplus10::CBase& operator--(int)\n"));
return *this;
}
};
}
上面的代码已经很好的说明了哪一些是前置调用重载,哪一些是后置调用的重载。
然后通过这些函数可以来看看一些哗众取宠的笔试题。
class_cplusplus10::CBase base;
++base++;
问++base++的调用是怎样的,通过调试发现,实际上后置++是先被调用,然后前置++。
不过这里是c++,而这种笔试题往往考的是操作符的优先级。也许一个对象和一个内置类型的变量存在一些不同
那个过chromium上的source tarball解压以后,在执行了gclient sync之后,在电脑A上面编译chrome工程ok。
然后执行clean,删除 build/debug下的所有文件,打压缩包。
保存到另一个电脑B上时,出现一大堆编译问题。
chromium的代码与编译脚本的生成太复杂,以至于有时候很难搞清楚到底要保留哪一些,要剔除哪一些。
现在想独立把chromium的代码拿下来然后做一个分支,发现太困难了。都搞了整个十一了,还没弄好,无奈至极!打算放弃!sh!t
以前我用的是网通对称10M,刚开始用的时候就发现路由力不从心,常常都是带宽还没有跑满。
后来发现10M的利用率越来越少,到期后就改成了4M。下面是我对我所在地网通的几个认识。
readmore
今天有空来整理了一下数据库。我偶然在数据库看到大学时期的博文。
回头看了一下,发现真是一个喜欢抱怨的小鬼。然后就开始逐条逐条的删起来了。
按理说这是我青春的印记,应该留下来以后没事的事情可以拿来回忆一下。
看着当时的博文,明显能够感受到曾经的无忧无虑和百无聊赖。这种生活相信是很多踏入社会后的人,可遇而不可求的。