我自己记录的C++笔记
一.关于New.试验环境.
1.建一个 C++ Win32 程序 (win32Con).
2.新建一个 .h 头文件.在里面写下列类.
class Dat
{
private:
double m_Len;
public:
Dat()
{
m_Len=0;
}
Dat(int len)
{
m_Len=len;
}
};
3.在 win32Con.cpp 文件中声明该类.现在分析声明类的方法,一般声明两种类型,声明一个指针和一个对象.如:
Dat* d1=new Dat(); //声明指针.
Dat d2=Dat(); //声明对象.
如此看来,两者的声明是有区别的. new 声明后返回的是一个指针吗? 用 sizeof() 试试!
std::cout<<sizeof(d1)<<endl; //输出 4 ,看来 new 返回的确实是一个指针.
std::cout<<sizeof(d2)<<endl; //输出 8 ,对象返回了一个对象的实体.
那在 Windows 系统对象(像 内核对象 thread , Process , file 都返回 handle )大小大多数都是4位的,那它们都是指针吗?
看 Windows 的 WinDef.h 文件.随便找一个简单的吧.
typedef struct tagSIZE
{
LONG cx;
LONG cy;
} SIZE, *PSIZE, *LPSIZE;
大都是这种结构.其中 最常用的是 PSIZE 和 LPSIZE .声明类的方法都是一样的.
SIZE* s1=new SIZE(); //声明指针.
SIZE s2=SIZE(); //声明对象.
这就是 Windows 的方法.所以如果用 new 关键字,必定返回一个指针.
4.在复制构造函数 Dat(Dat & D) 中,Dat一定要用引用类型.这是因为,只有在复制构造函数中,才能使用引用类型的私有变量.如
Dat(Dat & D)
{
m_Len=D.m_Len; //本来m_Len是私有变量,为什么可以在这可以被引用呢?
}
引用实际上就是变量的别名,这里有几条规则:
声明变量时必须初始化
一经初始化,引用不能在指向其它变量。
任何对引用的改变都将改变原变量。
引用和变量本身指向同一内存地址。
用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。
那么,在函数返回 引用类型时,返回的引用如何使用呢?
二.函数调用的问题.
1.在函数调用中,被调函数的参数是重新构造的.所以,在下列调用中,不会成功.
void GetMem(char * pchr) //在这里,相当于: void GetMem()
{ // {
pchr=(char *)malloc(100); // char * pchr=chr; //该处的chr是main中的chr. 但两个变量指向的是不同的内存地址.
} // pchr=(char*)malloc(100); }
void main()
{
char * chr=NULL;
GetMem (chr); //这样调用的话,在GetMem中有一次参数重构.
strcpy(chr,"abc");
cout<<chr<<endl;
}
以上相当于这样写:
void main()
{
char * chr=NULL;
char * pchr=chr; //@@@后注.
pchr=(char *) malloc(100);
strcpy(chr,"abc");
cout<<chr<<endl;
}
@@@:
两个变量 chr , pchr 所在的内存是不同的.所在内存的内容是一个内存地址. 这里的赋值是说,使两个变量所在内存的内容相同.我们的目的是想给两个变量都配同一块内存.所以 (char *) malloc(100) 应该指向两个变量所在内存的内容(是一个地址,也就相当于 &chr 或 &pchr).但是给内存地址赋值是不允许的.所以程序应该修改如下:
void main()
{
char * chr=NULL;
char ** pchr=&chr; //这就行了.
*pchr=(char *) malloc(100);
strcpy(chr,"abc");
cout<<chr<<endl;
}
2.函数调用的另一个问题.
char* GetMem(void)
{
char * pchr=(char*)malloc(100);
return pchr;
}
void main()
{
char * chr=GetMem();
strcpy(chr,"abc");
cout<<chr<<endl;
}
这样调用是成功的.为什么呢?该函数可以变化成如下形式.
void main()
{
char * chr =NULL;
char *p=(char*)malloc(100);
chr=p; //赋值的是两个变量所指向的内容(其实是一个地址).
free(p); //释放 p 所指向的地址.也就是说,经过 free(p); 后, p 就没有指向任何地址了.但是该变量是存在的.可以把它重新指向一个新的地址,并分配空间.
strcpy(chr,"abc");
cout<<chr<<endl;
}
3.函数调用的另一个问题.
void func(char[24] chr)
{
cout<<sizeof(chr)<<endl;
}
void main()
{
char * c="hello word!";
func(c);
}
//该程序会输出 4
4.在程序中所有声明的指针变量,均指向一个默认的地址.所以,在程序中所有声明的变量,都有相同的默认初始值.
所有变量定义后,都会指向一个地址.不能判断它是否已经初始化.
void main()
{
int *l;
int *k; //它们指向同一个地址.
cout<<l<<endl;
cout<<k<<endl;
int i1;
int i2;
cout<<i1<<endl;
cout<<i2<<endl; //返回同一个值.
}
三 API函数笔记.
十一.操作系统和编程环境设置:
1.设大硬盘Cache
BT会多线程地下载和上传,很多数据吞吐,Windows默认只有512KB的Cache显然不够,如果内存在256MB以上,开大一些Cache应该可以减少硬盘读写,提高性能。一般设在8-16MB效果最好。我设到32MB,开4个BT硬盘灯都不怎么闪。
a) 运行 "regedit";
b)去[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\IoPageLockLimit];
c) 根据你的内存修改其十六进制值:
8000为32MB,4000为16MB,其他数字按此计算。
补充计算转换方法如下:
1MB = 1024K,
10MB = 10240K
= 2800(16进制)
= 2*16^3 + 8*16^2 + 0*16^1 + 0*16^0 = 10240k (十进制)
d) 重启
如果没有找到IoPageLockLimit,就要新建,类型为DWord。
2.Windows 2000/XP/2003在默认情况下采用缩略图功能,但通过设置即可禁止在所有的图片文件夹中自动生成“Thumbs.db”文件:在“控制面板”中双击“文件夹选项”,在“文件夹选项”对话框中切换到“查看”标签,在“不缓存缩略图”复选框前打上“√”(如图),再点击“确定”按钮退出即可。
3.显示在列出成员的注释中
在C#.NET中类,属性,方法前面用///进行标记可做为注释,
而在C++中类在前面用//进行注释,属性,方法在后面用//进行注释.
十二.C++基础.
1. sizeof() 的问题.
char s1[256];
printf("%d\n",sizeof(s1)); //输出256
char *s2=new char[256];
printf("%d\n",sizeof(s2)); //输出4
printf("%d\n",sizeof(*s2)); //输出1
2.如何求得数组的长度.如
char* str=new char[1024]; //如何求得1024. strlen(str)-1
float * f=new float[12]; //如何求得 12.
3.关于指针与引用.
float * f=new float;
*f=13;
cout<<*f<<endl;
f=new float[12];
cout<<*f<<endl;
4. const throw() 的用法.
5. const 的用法.
1. const c 这种写法是定义一个常数,其默认是 const int c;
2. const char * c 这种写法是定义一个不可变的恒量
3. const char * const c 和 const char const * const c="hello";
4. 当你定义一个不修改变量的成员函数时,定义它为一个const成员函数是一个很好的办法,有两个好处:
1,可以保证这个函数的安全使用,因为它不改变变量的状态,比如,它不能给变量赋新值,不能分配内存或者激活析构函数.
2,提高程序的可读性:即使没有看到源代码,用户也可以明确此函数的实现目的.
一个例子:(one declaration and one definition of const member function shown):
class Person {
int age;
long social_security_n;
...
//改变变量状态
void setAge (int Age);
void setID(long ssn) { social_security_n = ssn; }
//访问变量,不能改变
int getAge () const; //不能修改变量
long getSocial_security_n () const {return social_security_n;}
};
6. public virtual 和 private virtual 的区别.
关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,现将本人的一些体会总结如下,期望对大家有所帮助:
一 const基础
如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:
int b = 500;
const int* a = &b; [1]
int const *a = &b; [2]
int* const a = &b; [3]
const int* const a = &b; [4]
如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。
另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法:A& operator=(const A& a);
void fun0(const A* a );
void fun1( ) const; // fun1( ) 为类成员函数
const A fun2( );
二 const的初始化
先看一下const变量初始化的情况
1) 非指针const常量初始化的情况:A b;
const A a = b;
2) 指针(引用)const常量初始化的情况:A* d = new A();
const A* c = d;
或者:const A* c = new A();
引用:
A f;
const A& e = f; // 这样作e只能访问声明为const的函数,而不能访问一般的成员函数;
[思考1]: 以下的这种赋值方法正确吗?
const A* c=new A();
A* e = c;
[思考2]: 以下的这种赋值方法正确吗?
A* const c = new A();
A* b = c;
三 作为参数和返回值的const修饰符
其实,不论是参数还是返回值,道理都是一样的,参数传入时候和函数返回的时候,初始化const变量
1 修饰参数的const,如 void fun0(const A* a ); void fun1(const A& a);
调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
[注意]:参数const通常用于参数为指针或引用的情况;
2 修饰返回值的const,如const A fun2( ); const A* fun3( );
这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
返回值用const修饰可以防止允许这样的操作发生:Rational a,b;
Radional c;
(a*b) = c;
一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
[总结] 一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。
原因如下:
如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
[思考3]: 这样定义赋值操作符重载函数可以吗?
const A& operator=(const A& a);
四 类成员函数中const的使用
一般放在函数体后,形如:void fun() const;
如果一个成员函数的不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。
五 使用const的一些建议
1 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4 const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5 不要轻易的将函数的返回值类型定为const;
6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;
本人水平有限,欢迎批评指正,可以联系 kangjd@epri.ac.cn
[思考题答案]
1 这种方法不正确,因为声明指针的目的是为了对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确;
2 这种方法正确,因为声明指针所指向的内容可变;
3 这种做法不正确;
在const A::operator=(const A& a)中,参数列表中的const的用法正确,而当这样连续赋值的时侯,问题就出现了:
A a,b,c:
(a=b)=c;
因为a.operator=(b)的返回值是对a的const引用,不能再将c赋值给const常量。
6. 如何捕获异常.当异常出现后,如何捕获所在的行?
7. #define 和 #typedef 有何区别.
#define 一个别名 后面跟一串文字 再跟一串文字
typedef 一串文字 再跟一串文字 最后是一个别名 ,最后加分号.
8. 字符型如何转换到Int , 如 int i = (int)"2"; (不行的.)如果是 BSTR转换到Int呢?
十二,一些想法
在破解 WinRar 密码的过程中, WinRar 的Dll ,我想是经过加壳处理的。用 OleView.exe 打不开 Dll
所以,只能用 暴力破解的方法了。用 VC 去发送消息。获取结果。
为了长时间运行。应该选择在计算机闲时运行。并且,记录运行的时刻。
|
作者:NewSea 出处:http://newsea.cnblogs.com/
QQ,MSN:iamnewsea@hotmail.com 如无特别标记说明,均为NewSea原创,版权私有,翻载必纠。欢迎交流,转载,但要在页面明显位置给出原文连接。谢谢。 |

浙公网安备 33010602011771号