结构体和类的区别--类和结构体定义的关键字不一样,类用“class”,结构体用“struct”,C语言中结构体中是不能包含函数的,但是C++语言里面结构体是可以包含函数的。结构体默认情况下,其成员是公有的“public”的,类在默认情况下,其成员是私有的private.在一个类中,公有成员是可以在类的外部访问的,而私有成员只能在类的内容进行访问了。类描述了一类事物,以及事物所对应的属性,类的对象是对类的具体化。类的实例和类的对象是一个概念。实例化一个对象就是产品一个对象,就是产生一个实例。面向对象的编程思路?到时是什么思路???
孙鑫里面的例子如果没有构造函数的话,那么类里面的成员变量值是不确定的。构造函数的作用是对类中的成员变量初始化,C++规定构造函数的名字和类名相同,即类名()。构造函数没有返回值。当我们定义一个对象的时候,会自动调用构造函数来对类中的成员变量赋初值。构造函数的作用是创建对象本身,C++规定每一个类必须有一个构造函数,没有构造函数就不能创建对象。
C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供),这个默认的构造函数一个不带参数的构造函数,他只负责创建对象,而不做任何初始化工作。只要一个类定义了一个构造函数,不管这个构造函数是否带参数的构造函数,C++就不再提供默认的构造函数。也就是说,如果为了一个类定义了一个带参数的构造函数,还想要无参数的构造函数,则需要自己定义。
VC++孙鑫的教程里面,通过加入断点,F10单步运行的方式来调试程序,可以看出当一个对象(如果是局部变量的话),当一个对象的生命周期结束后可以用析构函数来释放这个对象所占用的内存空间~类名()。比如孙鑫给出的例子,对象pt在void main()函数结束的时候自动调用了析构函数。析构函数不能有返回值,析构函数不能有函数参数。一个类中只能有一个析构函数。构造函数和析构函数都是系统来分配和回收内存空间的。构造函数可以有多个,根据函数的参数类型不同参数个数不同可以构成函数的重载。函数重载的条件是,函数的参数类型不同或者个数不同的时候。只有函数的返回类型不同是不能构成函数的重载的。
关于如何去解决变量的可见性问题,比如在一个类中的函数中为了要改变成员变量的值,可以考虑使用this指针。还没有看完,继续看。。。。。。。。。每一个对象的产生后,都有一个隐含的指针指向这个对象,this指针是一个隐含的指针,它是指向对象的本身,代表了对象的地址。如果一个类里面有多个对象,那么每一个对象都有一个this指针指向这个对象。this指针并不指向类,this指针是指向对象的,因为只有对象是占据着一定的内存空间的。this->XXX this所指向的成员函数XXX。this等同于&对象。一个类所有的对象调用的成员函数都是同一代码段。那么成员函数是怎么识别属于同一个对象的数据成员呢?原来,在对象调用pt.output(10,10)时,成员函数除了接受2个实参外,还接受了一个对象s的地址。这个地址被一个隐含的形参this指针所获取,他等同于执行this=&pt。所有对数据成员的访问都隐含地被加上前缀this->。例如:x=0;等价于this->0.
类的继承,class A:B, 类A派生于类B, A是派生类也叫子类,B是父类也叫基类。类的继承分为public,protected,privite三种。子类不能访问被保护的成员函数,protected不能在外部访问,但是可以在子类内部访问,privite只能在自己的类内部访问,public可以在外部和子类内部访问。
基类的访问特性 | 类的继承特性 | 子类的访问特性(基类的方法在子类中的访问特性) |
Public Protected Private | Public | Public Protected No access |
Public Protected Private | Protected | Protected Protected No access |
Public Protected Private | Private | Private Private No access |
基类的构造函数先构造,子类的构造函数再构造。在析构的时候正好相反,先析构子类的析构函数,再析构基类的析构函数。
Fish():Animal(400,300),a(1)
函数的覆盖:比如动物类有一个吃饭的方法,鱼呢有自己的吃饭的方法,这时候,在鱼里面从新写了这个方法,这里,从函数的名称,参数,返回值方法,子类和父类完全一样,这个叫做函数的覆盖。函数的覆盖是发生在父类与子类之间的。函数的重载是发生在一个类内部的。函数覆盖的好处是,以前父类的行为不太适合子类了,所以需要从新写这个行为。重新定义父类的函数。
在类外定义函数时,需要加上作用域运算符::,::表示这个函数是那个类的。 定义指向类对象的指针变量的一般形式为类名 *对象指针名 例如:animal *pAn 定义pAn为指向animal类对象的指针变量。
关于数据类型的转换,char cha字符型占用一个字节; int i 整型占用4个字节; 所以把整形转换成char型是不行的,因为会丢失3个字节的数据,但是从char到int是可以的。同样两个有继承关系的对象,比如animal对象的指针和fish对象的指针是一样的。
在基类的函数前加上virtual关键字,就把这个函数定义为虚函数。在派生类中重写该函数,运行时会根据对象的实际类型来调用相应的函数,如果对象的类型是派生类,就调用派生类的类型,如果对象的类型是基类,就调用基类的类型。虚函数用于派生类的函数和基类的函数名相同,但是里面的内容不一样的情况下,这时候,C++会采用延迟绑定的技术,根据对象的类型来决定是调用派生类还是基类的函数,这种延迟绑定的能力,也叫做C++的多态性。子类有的函数调用子类的,子类没有的调用基类的。
纯虚函数,指被标明为不具体实现的虚成员函数,比如:virtual void breathe()=0; 但是需要在派生类中定义纯虚函数。纯虚函数不叫座C++的多态性。当不太确定具体行为的是哪种形式的时候,可以把这个函数设定为纯虚函数,由派生类的函数来具体实现行为的形式。
C++中引用的概念,引用必须在定义的时候初始化,比如:int a=6; int &b=a;引用就是变量的一个外号。 注意,这个& and符号只有在定义的时候才是引用,在其他的时候就是取地址的付好了。
从上面的图可以看出,指针变量本身是需要有内存空间来存放它的,然而作为引用来说就不用。引用不需要占据内存空间。
引用用的比较多的是函数参数的传递,引用主要用在函数传参。
.h头文件中通常放入类的定义及类成员函数的声明,.cpp源文件中通常放入类成员函数的实现。 由于是要把类的实现也就是函数的实现放入到cpp源文件中,所以就会用到作用域运算符::,::表示这个函数是那个类的。也就说,类的构造函数和类里面的方法的实现都是在.cpp文件中的,所以就会出现很多的::作用域。我觉得这一块在学习对话框的编程的时候,可以更加仔细的看看。
“”和<>的区别是搜寻路径的起点区别,''''双引号-首先在工程当前目录下查找有没有.h文件然后在系统文件里面查找,<>不在当前目录下查找是在系统文件下查找。如果头文件是系统头文件直接用<>可以加快搜寻速度。如果不确定的头文件的位置的话,直接用""双引号。
避免出现类重复定义的方法是 #ifndef XXXX_XX_XX 如果没有定义XXXXX 那么定义#define XXXX_XX_XX --------#endif
VC++编译链接的原理及过程,首先,C++编译器对工程中的所有源文件(.cpp文件)单独进行编译(compiling),先由预处理器对预处理指令(#include,#define和#if)进行处理,在内存中输出翻译单元。编译器接受预处理的输出,将源代码转换成包含机器语言指令的三个目标文件(.obj文件),编译过程中头文件不参与编译。在Debug目录下可以找到生成的obj文件。接下来是链接过程(Linking......),链接器将目标文件和所用到的C++类库文件一起生成.exe文件。
#include <IOSTREAM.H>
class Point
{
public:
int x;
int y;
void init()
{
x=0;
y=0;
}
void output()
{
cout<<x<<endl<<y<<endl;
}
};
void main()
{
Point pt;
pt.init();
pt.x=3;
pt.y=3;
// cout<<pt.x<<endl<<pt.y<<endl;
pt.output();
}
#include<iostream.h>
class animal
{
public:
void eat()
{
cout<<"animal eat"<<endl;
}
void sleep()
{
cout<<"animal sleep"<<endl;
}
void breath()
{
cout<<"animal breath"<<endl;
}
};
class fish::public animal
{};
void main()
{
fish fh;
animal an;
an.eat();
an.breath();
an.sleep();
fh.eat();
fh.sleep();
fh.breath();
}