【C到C++】C到C++ 学习笔记 【概念】



简单清新的 类的使用教程:

http://wenku.baidu.com/link?url=M0XUEMDNI5wpeokI-rXSU0TAFiALzjOUP43iuS_mnFwET4fESwSwxE0eWcVmJjfcgpK7sL982XTRVi3ITm7pYKIlK_stw_IQDg2dEtCd_Zm### 



C++教程PDF下载

 http://www.kuaipan.cn/file/id_41753245395189798.html

4.4.5 名空间(namespace)
对于一个多文件构成的程序,有时会面临下面的问题:
1、在一个源文件中用到一个在另外一个源文件中定义的元素(如函数),而该元素的名
字与本源文件中定义的一个元素的名字相同。
2、在一个源文件中用到两个分别在另外两个源文件中定义的元素,而这两个元素具有
相同的名字。
为了解决上述的名冲突问题,C++提供了名空间(namespace)设施,即给一些定义
或声明取一个名字,当需要使用这些定义或声明的元素时,用相应的空间名字来受限。
如:
//file1.h
namespace A
{ void f();
void g();
}
//file1.cpp
namespace A
{ void f() { .......}
void g() { .......}
}
//file2.h
namespace B
{ void f();
void g();
}
//file2.cpp
namespace B
{ void f() { .......}
void g() { .......}
}
//main.cpp
57
#include "file1.h"
#include "file2.h"
void main()
{
A::f(); //file1中定义的f
A::g(); //file1中定义的g
B::f(); //file2中定义的f
B::g(); //file2中定义的g
}
如果在某个名空间中定义了很多元素,这时,会给使用这些元素带来不便。为了简
化书写,当使用某个名空间上的元素时,可在使用前写一个 using 指示项,使得今后使
用相应名空间中的元素时不必用空间名受限,如:
void main()
{ using namespace A;
f(); //file1中定义的f
g(); //file1中定义的g
B::f(); //file2中定义的f
B::g(); //file2中定义的g
}
也可以分别对某个名空间中的元素采用 using 声明,如:
void main()
{ using A::f;
f(); //file1中定义的f
A::g(); //file1中定义的g
B::f(); //file2中定义的f
B::g(); //file2中定义的g
}

 

 

宏定义注意:
(1) 采用宏定义时,如果一行写不下,在本行最后用续行符“\”转到下一行。
(2) 宏定义是文本替换,应加上必要的括号。
例如:用上面的max宏定义,下面的表达式:
10+max(x,y)+z
将替换成:
10+a>b?a:b+z
它与要求不符,因此,上面的max宏定义是不可靠的,应该定义为:
#define max(a,b) (((a)>(b))?(a):(b))
--------------------------------
#define multiply(a,b) a*b

multiply(x+y,m-n) // x+y*m-n
宏定义的缺点:
(1) 重复计算。
(2) 参数类型检查不足。

 

 

2、内联函数
在函数定义前加上关键字 inline,建议编译器把函数体扩展到调用点。内联函数具
有宏和函数二者的优点。
注意:
(1) 何时使用内联函数?
(2) 编译器对内联函数的限制
(3) 在内联函数的调用点一定要见到内联函数的定义。

 

 

4.7 函数重载(Overloading)
1、定义
在同一个作用域中定义的多个名字相同、参数不同的函数,它是 C++提供的一种多
态机制(论域中的一个元素有多种解释)。
函数重载主要用于功能相同而参数不同的多个函数的定义。
例如:
int add(int x, int y)
{ return x+y;
}
double add(double x, double y)
{ return x+y;
}

 

 

 

 

 1、

#include  <</SPAN> iostream.h>用于告诉编译程序在本程序中包含标准输入输出 库的有关信息。许多C源程序的开始处都包含这一行。

(3) 程序的第 using namespace std;的意思“使用命名空间 stdC++

标准库中的类和函数是在命名空间 std 中声明的因此程序中如果需要用

 

 

 

 

 

 

 

 

 C++标准库就需要using namespace std;作声明表示要用到命名

空间 std 中的内容。

成员函数的定义可以放在类定义中,也可以放在类定义外。
1、在类定义中定义成员函数。
class CDate
{ public:
void SetDate(int y, int m, int d)
{ year = y;
month = m;
day = d;
}
int IsLeapYear()
{ return (year%4 == 0 && year0 != 0) || (year@0==0);
116
}
void Print()
{ cout<<year<<"."<<month<<"."<<day<<endl;
}
private:
int year,month,day;
};
如果成员函数的定义放在类定义中,则表示建议编译程序按内联函数处理之。
2、在类定义外定义成员函数:
如果在类定义外定义成员函数,则在类定义中应给出成员函数的声明,并且在类定
义外定义成员函数时,应在返回类型和函数名之间加上:
<类名>::
如:
class CDate
{ public:
void SetDate(int y, int m, int d);
int IsLeapYear();
void Print();
private:
int year,month,day;
};
void CDate::SetDate(int y, int m, int d)
{ year = y;
month = m;
day = d;
}
int CDate::IsLeapYear()
{ return (year%4 == 0 && year0 != 0) || (year@0==0);
}
void CDate::Print()
{ cout<<year<<"."<<month<<"."<<day<<endl;
}
一般情况下,类定义放在头文件(.h)中,类外定义的成员函数放在实现文件(.cpp)
中。

 

 

 

 

 

 

 

Student stud1,stud2;

int   main ()

{

 

stud1.setdata(  );                    //调用对象  stud1  setdata 函数

stud2.setdata(  );                    //调用对象  stud2  setdata 函数 

stud1.display(  );                    //调用对象  stud1  display  函数 

stud2.display(  );                    //调用对象  stud2  display  函数 return  0;

}

 

 

 

 

 

程序说明:

 

 

(1) 在一个类中包含两种成员:数据和函数,分称为数据成员和成员函数。

在 C++把一组数据和有权调用这些数据函数封装在一起,组成一种称 为“(class)”的数据结构.在上面的程序中,数据成员 num,score 和成员函 数 setdata,display 组成了一个名为 Student “类类型成员函数是用来对 数据成员进行操作的。也就是说,一个类是一批数据以及对其操作的函 数组成的。

(2) 类可以体现数据的封装性和信息隐蔽。在上面的程序中,在声明 Student 类时,把类中的数据和函数分为两大类:private(私有的) public(公用把全部数据(num,score)指定为私有的,把全部函数(setdata,display) 指定为公用的在大多数情况下会把所有数据指定为私有以实现信息隐蔽。具有“类”类型特征的变量称为“对象”(object)

 

(5)类(class)是 C++新增加的重要的数据类型,是 C++对 C 的最重要的发展。有 了类就可以实现面向对象程序设计方法中的封装信息隐蔽继承派生多 态等功能在一个类中可以包括数据成员和成员函数他们可以被指定为私有的 (private)和公用的(public)属。私有的数据成员和成员函数只能被本类的成 员函数所调用。

 

 

 

 

6.2.4 成员的访问控制:信息隐藏
在 C++的类定义中,可以用访问控制修饰符 public,private 和 protected 对类成员
的访问进行限制。
1、public
对 public 成员的访问不受限制。
2、private
private 成员只能在本类和友元中访问。
3、protected
protected 成员只能在本类、派生类和友元中访问。
例如:
class A
{ public:
int x;
void f() { 允许访问:x,y,z,f,g,h }
private:
int y;
void g() { 允许访问:x,y,z,f,g,h }
protected:
int z;
void h() { 允许访问:x,y,z,f,g,h }
};
......
A a;
a.x = 1; //OK
a.f(); //OK
a.y = 1; //Error
a.g(); //Error
a.z = 1; //Error
a.h(); //Error
在类定义中,可以有多个 public、private 和 protected 访问控制声明,C++的默
认访问控制是:private

 

 

 

6.3.1 构造函数
1、对象的初始化
对象的初始化是指对象数据成员的初始化。在创建对象后、使用对象前,往往要对
对象的某些数据成员进行初始化。 

 

2、构造函数的定义
构造函数是指:在对象类中定义或声明的与类同名、无返回类型的函数。当创建对
象时,构造函数将被自动调用。对构造函数的调用是对象创建过程的一部分,不能在其
它地方调用构造函数。例如:
class A
{ int x;
public:
A() { x = 0; } //构造函数
......
};  

 

构造函数可以重载,其中,不带参数的构造函数被称为默认构造函数。当对象类中
未提供任何构造函数时,编译程序将为之提供一个默认构造函数。如果对象类中提供了
构造函数,但没有提供默认构造函数,编译程序将不再为其提供默认构造函数。

 

3、构造函数的调用
在创建对象时,构造函数将自动被调用,所调用的构造函数在创建对象时指定。
例:
class A
{ …
public:
A();
A(int i);
A(char *p);
};
A a1; ÙA a1=A(); //调A(),注意:不能写成:A a1();
A a2(1); ÙA a2=A(1); ÙA a2=1; //调A(int i)
A a3(“abcd”); ÙA a3=A(“abcd”); ÙA a3=“abcd”; //调A(char *)
A a[4]; //调用a[0]、a[1]、a[2]、a[3]的A()
A b[5]={A(),A(1),A("abcd"),2,"xyz"}; //调用b[0]的A()、b[1]的A(int)、
//b[2]的A(char *)、b[3]的A(int)和b[4]的A(char *)。
126

 

 

4、成员初始化表
在定义构造函数时,函数头和函数体之间可以加入一个对数据成员进行初始化的
表,用于对数据成员进行初始化,特别是对常量和引用数据成员进行初始化。
例:
class A
{ int x;
const int y;
int& z;
public:
A(): y(1),z(x), x(0) { … }
};
注:对x的初始化可以放在成员初始化表中,也可以在构造函数体中进行赋值。
数据成员初始化的次序取决于它们在类定义中的声明次序,与它们在成员初始化表
中的次序无关。

 

 

6.3.3 成员对象的初始化
类的数据成员可以是另一个类的对象。
1、初始化
成员对象的初始化在包含该成员对象的对象类中指定。默认情况下调用成员对象的
默认构造函数,如需要调用成员对象的非默认构造函数,则需要在包含该成员对象的对
象类构造函数的成员初始化表中指定。
例:
class A
{ int m;
public:
A() { m = 0; }
A(int m1) { m = m1; }
};
class B
{ int x;
A a;
public:
B() { x = 0; }
129
B(int x1) { x = x1; }
B(int x1, int m1): a(m1) { x = x1; }
};
void main()
{ B b1; //调用B::B()和A::A()
B b2(1); //调用B::B(int)和A::A()
B b3(1,2); //调用B::B(int,int)和A::A(int)
…...
}

 

 

、构造函数与析构函数的调用次序
当创建包含对象成员的对象时,先调用成员对象的构造函数,再调用本身对象的构
造函数。当包含对象成员的对象消亡时,先调用本身对象的析构函数,再调用成员对象
的析构函数。

 

6.4 友元
    在一个类的外部不能访问该类的 private 成员,如需访问,则须通过该类的 public
成员来进行,这个限制有时会降低对 private 成员的访问效率,缺乏灵活性。

在一个类定义中,可以指定某个全局函数、某个其它类或某个其它类的某个成员函
数可以访问该类的私有和保护成员,即友元函数、友元类和友元类成员函数。

例:
......
void func() {…}
class A
{ …
friend void func(); //友元函数
friend class B; //友元类
friend void C::f(); //友元类成员函数,假定void f()是类C的成员函数
};
友元的作用在于提高面向对象程序设计的灵活性,是数据保护和对数据的存取效率
之间的一个折中方案。
注意:友元不具有传递性,即,假设B是A的友元、C是B的友元,如果没有显式指
136
出C是A的友元,则C不是A的友元。

 

 

6.5 动态对象
在程序的堆(Heap)中创建的对象称为动态对象。动态对象用 new 操作符创建,用
delete 操作符撤消。
1、单个动态对象的创建与撤消
class A
{ …
public:
137
A();
A(int);
};

A *p,*q;
p = new A; // 首先在程序的堆中申请一块大小为sizeof(A)的
// 空间,然后调用A的默认构造函数对该空间上的对
// 象初始化,最后返回创建的对象的地址并赋值给p。
q = new A(1); // 与上一条类似,不同之处在于:不是调用A的
// 默认构造函数,而是调用A的另一个构造函数:
// A::A(int)。

delete p; // 首先调用p所指向的对象的析构函数,然后释放对
// 象空间。
delete q; // 与上一条相同。
动态对象也可以采用 C++的库函数 malloc 来创建和 free 来撤消:
p = (A *)malloc(sizeof(A));
free(p);
但是,malloc 不调用 A 的构造函数,free 不调 A 类的析构函数,因此,对象的初
始化和结束处理只能采用其它方式实现。
另外,new 操作符的优越性还在于:
(1) 自动分配足够的空间
(2) 自动返回指定类型的指针
(3) 可以重载

 

2、动态对象数组的创建与撤消
A *p;
p = new A[100];
delete []p;
new 的一般形式:
new [size_1][size_2]…[size_n]
注意:
138
(1) 不能显式地初始化对象数组,相应的类必须有默认构造函数。
(2) delete中的[]不能省。

 

6.7 静态成员
对象是类的实例,类刻划了一组具有相同属性的对象。
类中声明的成员变量属于实例化后的对象,有多个拷贝(拷贝个数由创建的对象个
数决定)。
问题:同一个类的不同对象如何共享变量?如果把这些共享变量定义为全局变量,则缺
乏数据保护,因为其它类的对象往往也能存取这些全局变量。
1、静态成员变量
class A
{ int x,y;
static int shared;
.....
};
int A::shared=0;
A a,b;
类定义中声明的静态变量被该类的对象所共享,即,对该类的所有对象,类的静态
成员变量只有一个拷贝。静态变量也遵循类的访问控制。
2、静态成员函数
class A
{ static int shared;
int x;
public:
static void f() { …shared…}
void q() { …x…shared…}
};
140
静态成员函数只能存取静态成员变量和调用静态成员函数。静态成员函数也遵循类
的访问控制。
3、静态成员的使用
(1) 通过对象使用
A a;
a.f();
(2) 通过类使用
A::f();

 

 

2012.8.16 引用 

 

   引用类型 (reference type)  “引用”(reference)是c++的一种新的变量类型,是对C的一个重要补充。它的作用是为变量起一个别名。假如有一个变量a,想给它起一个别名,可以这样写:

int a;int &b=a;

 

这就表明了b是a的“引用”,即a的别名。,&是“引用声明符”,并不代表地址。不要理解为“把a的值赋给b的地址”。引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。声明引用并不开辟内存单元,b和a都代表同一变量单元。

 

引用和指针的区别  

看实例吧:

  引用是C++中的概念,初学者容易把引用和指针混淆一起。

  下面的程序中,n是m的一个引用(reference),m是被引用物(referent)。

  int m;

  int &n = m;

  n相当于m的别名(绰号),对n的任何操作就是对m的操作。

  所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。

 

http://baike.baidu.com/view/160006.htm

 

2、在成员函数中访问类成员
在一个类的成员函数中访问该类的成员(数据成员和成员函数),直接访问即可,
如:
class A
{ public:
void f();
void q(int i) { x = i; f(); }
private:
int x;
};
......
A a,b;
a.q(1); //在A::q中访问的是a.x
b.q(2); //在A::q中访问的是b.x
119
问题:
对于下面的非成员函数 func:
void func(A *p)
{ …
p->q(1);

}
如果在 A::f 中调用 func,即:
class A
{ public:
int x;
void f() { func(...);}
void q(int i) { x = i; f(); }
};
对于:
A a,b;
要求:
(1) 当调用a.f()时,在A::f中调用func(&a)
(2) 当调用b.f()时,在A::f中调用func(&b)
如何给出 A::f 中调用 func 的参数?

 

this 指针


在 C++的类定义中引进了 this 指针变量,每个成员函数中都有一个隐含的形参
this,其类型为相应类的指针常量(对于上述的类 A,this 的类型为 A * const)。当一
成员函数被调用时,编译系统自动把调用的对象地址传给 this。例如,对于 a.f(),
编译器将把它编译成:
A::f(&a);
因此,在 A::f 中调用 func 时,可把 this 作为参数调用 func,即:func(this),
就能实现所要求的功能。
实际上,在成员函数中访问类数据成员时,应该写成:this-><数据成员名>


一般情况下,this->可以省略,但要把对象作为整体来访问时必须显式给出 this。

 

VARIANT型变量  2012.8.11

    实际上VARIANT也只不过是一个新定义的结构罢了,它的主要成员包括一个联合体及一个变量。该联合体由各种类型的数据成员构成,而该变量则用来指明联合体中目前起作用的数据类型。我们所关心的接收到的数据就存储在该联合体的某个数据成员中。该联合体中包含的数据类型很多,从一些简单的变量到非常复杂的数组和指针。由于通过串口接收到的内容常常是一个字节串,我们将使用其中的某个数组或指针来访问接收到的数据。这里推荐给大家的是指向一个SAFEARRAY(COleSafeArray)类型变量。新的数据类型SAFEARRAY正如其名字一样,是一个“安全数组”,它能根据系统环境自动调整其16位或32 位的定义,并且不会被OLE改变(某些类型如BSTR在16位或32位应用程序间传递时会被OLE翻译从而破坏其中的二进制数据)。大家无须了解SAFEARRAY的具体定义,只要知道它是另外一个结构,其中包含一个 (void *)类型的指针pvData,其指向的内存就是存放有用数据的地方。

   简而言之,从GetInput()函数返回的VARIANT类型变量中,找出parray 指针,再从该指针指向的SAFEARRAY变量中找出pvData指针,就可以向访问数组一样取得所接收到的数据了。具体应用请参见void CSCommTestDlg::OnComm()函数。

void CSCommTestDlg::OnComm()
{
// TODO: Add your control notification handler code here
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048];
//设置BYTE数组 An 8-bit integerthat is not signed.

CString strtemp;
if(m_ctrlComm.GetCommEvent()==2)//事件值为2表示接收缓冲区内有字符
{
variant_inp=m_ctrlComm.GetInput(); //读缓冲区
safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
len=safearray_inp.GetOneDimSize(); //得到有效数据长度
for(k=0;k
safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组
for(k=0;k
{
BYTE bt=*(char*)(rxdata+k); //字符型
strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
m_strRXData+=strtemp; //加入接收编辑框对应字符串
}
}
UpdateData(FALSE); //更新编辑框内容
}  


 

 

http://hi.baidu.com/mangshe0/blog/item/b9c8bccb067136f352664faf.html

 

 2012.8.15

 

(1) a.*b:a是一个对象,b是一个类成员指针。含义是:访问对象a的由b指向的成员。
(2) a->*b:a是一个对象指针,b是一个类成员指针。含义是:访问a所指向对象的由
143
b指向的成员。
例:
class A
{ public:
int x;
void f();
};
......
int A::*pm_x = &(A::x);
void (A::*qm_f)() = &(A::f);
A a;
A *p=new A;
a.x = 0;
a.*pm_x = 0;
a.f();
(a.*qm_f)();
p->x = 0;
p->*pm_x = 0;
p->f();
(p->*pm_f)();

2012.8.15 c++的函数指针和类的成员函数的指针

函数指针实例:

typedef int (*p)(int,int);//定义一个接受两个int型且返回int型变量的函数指针类型
int func(int x,int y)
{
printf("func:x=%d,y=%d/n",x,y);
return (x
}

int main()
{
p fun=func;//定义函数指针并给它赋上一个函数指针
cout<<"min:"<<(*fun)(4,5)<<endl;//为什么*fun需要用()扩起来呢?因为*的运算符优先级比()低,如果不用()就成了*(fun())
return 0;
}

而“指向类成员函数的指针”却多了一个类的区别:

class A
{
public:
int func(int x,int y)
{
printf("A::func:x=%d,y=%d/n",x,y);
return (x
}
};
typedef int (A::*p)(int,int);//指针名前一定要加上所属类型类名 A::的限定

int main()
{
p fun=&A::func;
A a; //因为成员函数地址的解引用必须要附驻与某个对象的地址,所以我们必须创建某个对象。
cout<<"min:"<<(a.*fun)(4,5)<<endl;
return 0;
}

 

更多:

http://wenku.baidu.com/view/de768f71a417866fb84a8e65.html

 

 2012.8.15

 8.2 基类与派生类(父类与子类)  基类就是父类

 

· 派生类是基类的具体化,派生类是基类的延续.

派生类拥有基类的全部属性,并可以添加自己特有的属性。举个例子,VC++中CDialog(对话框类)就是从CWnd(窗口类)派生来的,因为对话框有窗口的所有属性,又有自己特殊的属性。

 

对于下面的两个类A和B,A是基类,B是派生类。
class A //基类
{ int x,y;
public:
f();
g();
};
class B: public A //派生类
{ int z;
public:
h();
};

B b;
b.f(); //A中的f
b.h(); //B中的h


派生类对象除了拥有基类对象的所有成员外,还可以具有新的成员。例如:B类的对象b具有成员变量x、y和z以及成员函数f、g和h。

 

派生类的定义用于描述派生类与基类的差别,在C++中,派生类中可以给出新的成员,也可以对基类的成员进行重定义:
class B: public A
{ int z;
public:
h();
f();
};

b.f(); //B中的f。

 

对于基类的一个成员函数,如果派生类中没有定义与其同名的成员函数,则该成员函数在派生类的作用域内可见,否则,该成员函数在派生类的作用域内不可见,如果要使用之,必须用基类名受限:
b.A::f(); //A中的f

即使派生类中定义了与基类同名但参数不同的成员函数,基类的同名函数在派生类的作用域中也是不可见的:
class B: public A
{ …
public:
h() { f(1); A::f(); }
f(int);
};

B b;
b.f(1); //Ok
b.f(); //Error
b.A::f(); //Ok

 

 

int main(){

  void (*fun)(A*);

  A *p=new B;

  long lVptrAddr;

  memcpy(&lVptrAddr,p,4);

  memcpy(&fun,reinterpret_cast(lVptrAddr),4);

  fun(p);

  delete p;

  system("pause");

  }

void (*fun)(A*); 这段定义了一个函数指针名字叫做fun,而且有一个A*类型的参数,A* p=new B; new B是向内存(内存分5个区:全局名字空间,自由存储区,寄存器,代码空间,栈)自由存储区申请一个内存单元的地址然后隐式地保存在一个指针中.然后把这个地址赋值给A类型的指针P.

  fun(p); 这里就调用了刚才取出的函数地址里的函数,也就是调用了B::fun()这个函数,也许你发现了为什么会有参数p,其实类成员函数调用时,会有个this指针,这个p就是那个this指针,只是在一般的调用中编译器自动帮你处理了而已,而在这里则需要自己处理。

 

 8.3.2 在派生类中对基类成员的访问


   在派生类中可以使用基类的public成员,但不能使用基类的private成员。


  在派生类中定义新的成员或对基类的成员重定义时往往需要用到基类的一些private成员,解决这个问题的一种办法是在基类中开放这些成员(声明为public),但这样就带来一个问题:数据保护的破坏。当基类的内部实现发生变化时将会影响子类用户和基类的的实例用户。
为了缓解上述问题的严重性,
在C++中引进了protected成员保护控制,在基类中声明为protected的成员可以被派生类使用,但不能被基类的实例用户使用,这样缩小了修改基类的内部实现所造成的影响范围(只影响子类)。
另外,引进protected后,基类的设计者也会慎重地考虑应该把那些成员声明为protected,至少应该把今后不太可能发生变动的、有可能被子类使用的、不宜对实例用户公开的成员声明为protected。

 

8.4 多继承

 

class D: public B, public C
{

int r;
public:
fd();
};

 

8.4.3 名冲突


用<基类名>::<基类成员名>解决。如:


class A
{ ......
public:
f();
g();
};
class B
{ ......
public:
f();
h();
};
class C: public A, public B
{ ......
public:
func()
{ A::f();
g();
B::f();
h();
}
};
......
C c;
c.func();
c.A::f();
c.g();
8.4.4 虚基类
c.B::f();
c.h();

 

2012.8.16  托管堆

 

 .NET框架包含一个托管堆,所有的.NET语言在分配引用类型对象时都要使用它。像值类型这样的轻量级对象始终分配在栈中,但是所有的类实例和数组都被生成在一个内存池中,这个内存池就是托管堆。
  垃圾收集器的基本算法很简单:
  ● 将所有的托管内存标记为垃圾
  ● 寻找正被使用的内存块,并将他们标记为有效
  ● 释放所有没有被使用的内存块
  ● 整理堆以减少碎片
http://www.tudou.com/home/diary_v9913437.html

     由于托管堆的天性,对象们总是被分配在连续的地址上,托管堆总是保持紧凑,结果使得对象们始终彼此靠近,永远不会分得很远。这一点与标准堆提供的非托管代码形成了鲜明的对比,在标准堆中,堆很容易变成碎片,而且一起分配的对象经常分得很远。

 

2012.8.16  this指针

 

全局仅有一个this指针,当一个对象被创建时,this指针就指向对象数据的首地址。

void MovePoint( int a, int b){ x+=a; y+=b;}

    MovePoint函数的原型应该是 void MovePoint( Point *this, int a, int b);第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的。这样point1的地址传递给了this,所以在MovePoint函数中便显式的写成:

  void MovePoint(int a, int b) { this->x +=a; this-> y+= b;}

 

   当一个成员函数被调用时,编译系统自动把调用的对象地址传给this。例如,对于a.f(),编译器将把它编译成:
A::f(&a);

 

  实际上,在成员函数中访问类数据成员时,应该写成:
this-><<FONT color=#ed1c24>数据成员名>
一般情况下,this->可以省略,但要把对象作为整体来访问时必须显式给出this。

 

这里的this不能省略,如果省略了就相当于自赋值了
如下程序:
#include 
#include 
using namespace std;
class aa
{
 private:
   int year;
 public:
   void changeyear(int year)
    {
     this->year = year; //将形参year赋值给类成员变量year,如果省略了this->,那么成员变量year未初始化
    }

   void print() const
   {
           cout << year << endl;
   }
};

void main()
{
        aa b;
        b.changeyear(10);
        b.print();
} 

 

http://baike.baidu.com/view/2140472.htm

 

添加this指针的好处:

  为什么程序里好多不必要的“this->”?
这是因为集成开发环境有自动提示功能,在遇到“.”和“->”的时候能自动列出所有成员的名字,这样程序员就可以从列表里选择,不用一个一个字母输入了,而且不容易出现拼写错误,所以很多人就喜欢写“this->”了。
  表达明确,是在说这个CreateGraphics()是我的成员函数哦,可不是什么全局函数或者其他东西。

 

2012.8.16  void ...const; 

 

virtual void AssertValid() const; 

首先这个加const表示,函数内部所操作的成员变量时不可更改的,确保变量的值不变。

 

函数的作者在后面加个throw(), 就是在告诉你"这个函数不抛异常, catch什么的是不必要的"


 

关于 typedef struct 和 struct   2012.9.3


请高手帮忙解释以下几种结构体定义的区别:

struct{

  int x;

  int y;

}test1;


struct test

{int x;

int y;

}test1;


typedef struct test

{int x;

int y

}text1,text2;

这几种方法把小弟弄得头疼,不胜感激!

问题补充:

还有:

type struct

{int x;

int y;

}test1;

我来帮他解答

  2008-4-4 03:24 满意回答

(1) struct{ int x; int y; }test1; 

好,定义了 结构 test1,

test1.x 和 test1.y 可以在语句里用了。


(2) struct test {int x; int y; }test1; 

好,定义了 结构 test1,

test1.x 和 test1.y 可以在语句里用了。

与 1 比,省写 了 test


(3) 

typedef struct test 

{int x; int y;  // 你漏打分号,给你添上 

}text1,text2; 

只说了 这种结构 的(类型)别名 叫 text1 或叫 text2


真正在语句里用,还要写:

text1 test1;

然后好用 test1.x test1.y


或写 text2 test1;

然后好用 test1.x test1.y


(4)type struct {int x; int y; }test1;

这个不可以。

改 typedef ... 就可以了。

但也同 (3)一样,还要 写:

test1 my_st;

才能用 my_st.x 和 my_st.y

 

//-----------------------------------------未验证----------------------------------------------//

临时学习指导:

可以参考一下
这些程序是我自己一个一个写的,现拿出来让和我一样的初学者分享一下,用的是dev C++ 编译,里面包括详细的

分析过程和代码注释,有两个文件,一个是c++/c 基础的,另一个是基础提高篇,我相信对初学者是有很大的帮助

的! 同时里面有运行的图片,下载的同学可以先看题目,然后在自己去做,在和我比较一下思路,我写的不是很好

的地方还望赐教

下载地址:http://tangxianghenggood.download.csdn.net/

下面的是强化训练
这个系统是用DEV c++ 写的,上面注释也很详细,对于练技术还是很有用的,以前看很多人说做dos没界面,不好用

,这个可以让你深刻的学习一下的!直接用dev c++ 打开 可以直接编译运行

http://d.download.csdn.net/down/2746868/tangxianghenggood

可以训练的好帮手,

posted on 2022-10-04 01:30  bdy  阅读(122)  评论(0编辑  收藏  举报

导航