阿蓉之从零开始的【VC++ 】—— 结构体和类

ε=(´ο`*)))唉,看不懂tmc13代码,随便在柜子里找了一本年代久远的书,快速过一下前两章,零散的记录一些,书里讲的还是很循序渐进的,学到了一些之前不知道或已经忘了的,真好,一个个字和代码敲出来,敲字不易呀。


第一章

1、API函数( Application Programming Interface),应用程序编程接口

2、SDK(Software Development Kit),软件开发包

3、句柄Handle,相当于资源的标识号。窗口句柄HWND,若要对某个窗口进行操作,需要得到这个窗口的句柄。

4、C++是面向对象的语言。C++与C相比有很多优点,主要体现在封装性(Encapsulation),继承性(Inheritance)、和多态性(Polymorphism)。


第二章

1、从结构到类

c语言中,结构体中的变量,可以是相同、部分相同,或完全不同的数据类型。c++对其进行了扩展,C++的结构体可以包含函数

C++中预定义了三个标准输入输出流对象:cin(标准输入),cout(标准输出),cerr(标准错误输出)。所以需要包含iostream.h这个头文件。

结构体的定义:

#include <iostream.h>
struct point
{
    int x;
    int y;
};
void main
{
    point pt;
    pt.x=0;
    pt.y=0;
    cout<<pt.x<<endl<<pt.y<<endl;
} 

结构体中加入函数:

#include <iostream.h>
struct point
{
    int x;
    int y;
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
};
void main
{
    point pt;
    pt.x=0;
    pt.y=0;
    //cout<<pt.x<<endl<<pt.y<<endl;
    pt.output();
} 

 的定义:

class point
{
    int x;
    int y;
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
};

类和结构体的定义很相似,分别用关键字“class”和“struct”来定义,最重要的差别在于成员的访问控制有所差异。在默认情况下,结构体的成员是公有的public,类的成员是私有的private。类中,公有成员可在类外进行访问,私有成员只能在类内部。

运行下面这个程序会报错,会提示不能访问类中的私有的成员变量和成员函数。

#include <iostream.h>
class point
{
    int x;
    int y;
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
};
void main
{
    point pt;//定义了pt对象,它的类型是point这个类。
    pt.x=0;
    pt.y=0;
    pt.output();
}

//error!!! 
//在int x;的上一行顶格添加“public:”

2、C++的特性

类与对象类描述了一类事物及事物对应的属性。例如电脑这个类包含显示器、主板、CPU、内存、硬盘等,而如果我们组装的是一台具体的电脑,这个电脑显示器是美格的,主板是华硕的、CPU是Intel的,内存是现代的、硬盘是希捷的,这台具体的电脑就是这个类的一个对象。类的实例和类的对象是一个概念。对象是可以销毁的,而类不行。

构造函数:构造函数用来对类中的成员变量进行初始化(对对象本身做初始化工作)。C++规定构造函数的名字和类名相同,没有返回值。

#include <iostream.h>
class point
{
    int x;
    int y;
    point()  //point类的构造函数,没有任何返回值
    {
        x=0;
        y=0;
    }
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
};
void main
{
    point pt;//定义了pt对象,它的类型是point这个类。
    //pt.x=0;
    //pt.y=0;//省去这里的初始化
    pt.output();
}
//可以看到输出结果是两个0

析构函数:析构函数与构造函数作用相反,用于清除类的对象,释放对象占用的资源。析构函数不允许有返回值,不允许带参数,一个中只能有一个析构函数。定义格式:~类名(),譬如:~point()。

对于一个对象来说析构函数是最后一个被调用的成员函数。

class Student
{
private:
    char *pName;
public:
    Student()
    {
        pName=new char[20];//给字符指针变量pName在堆上分配20个字符的内存空间
    }
    ~Student()
    {
        delete[] pName;
//如果没有这句,当定义一个Student对象,对象生命周期结束时,他的构造函数中分配的这块堆内存就回丢失,造成内存泄露。
    }
};

函数的重载(overload):两个函数函数名相同,但参数的类型和个数不同,C++编译器会根据参数类型和个数来确定执行哪一个函数。注意,只有函数的返回类型不同是不能构成函数的重载的。

如,void output();  int output(); 不能构成。void output(int a,int b=5);  void output(int a);  不能构成。

#include <iostream.h>
class point
{
    int x;
    int y;
    point() 
    {
        x=0;
        y=0;
    }
    point(int a,int b) //函数重载
    {
        x=a;
        y=b;
    }
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
};
void main
{//构造pt的同时,传递xy值。执行point(int a,int b)这个函数
    point pt(5,6);
    pt.output();
}
//输出结果是5和6

this指针:是一个隐含的指针,指向对象本身,代表对象的地址。所有对数据成员的访问都隐含的被加上了前缀this->

#include <iostream.h>
class point
{
    int x;
    int y;
    point() 
    {
        x=0;  //等价于this->x=0
        y=0;
    }
    point(int a,int b) //函数重载
    {
        x=a;
        y=b;
    }
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
    void input()
    {
        x=x;
        y=y;
    }
};
void main
{
    point pt(5,6);
    pt.input(10,10);
    pt.output();
}

//输出结果是5和6
//因为变量的可见性,point类的成员变量xy在input中是不可见的,所以实际上input函数是将形参xy赋给了形参xy
#include <iostream.h>
class point
{
    int x;
    int y;
    point() 
    {
        x=0;  //等价于this->x=0
        y=0;
    }
    point(int a,int b) //函数重载
    {
        x=a;
        y=b;
    }
    void output()
    {
        cout<<pt.x<<endl<<pt.y<<endl;
    }
    void input()
    {
        this->x=x;
        this->y=y;
    }
};
void main
{
    point pt(5,6);
    pt.input(10,10);
    pt.output();
}
//输出结果10,10

类的继承:对于动物类、绵羊类、鱼类都具有吃、睡、呼吸,但不用一个个的重写代码。可以基于animal类来创建fish类。animal被称为基类(Base Class,或父类),fish为派生类(Derived Class,或子类

#include <iostream.h>
class animal
{
public:
    void eat()
    {
        cout<<"animal eat"<<endl;
    }
    void sleep()
    {
        cout<<"animal sleep"<<endl;
    }
    void breathe()
    {
        cout<<"animal breathe"<<endl;
    }   
};

class fish:public animal
{//fish类
};

void main
{
    animal an;
    fish fh;
    an.eat();
    fh.eat();
}

添加构造函数和析构函数:

#include <iostream.h>
class animal
{
public:
    animal()//构造函数
    {
        cout<<"animal construct"<<endl;
    }
    ~animal()//析构函数
    {
        cout<<"animal destruct"<<endl;
    }
    void eat()
    {
        cout<<"animal eat"<<endl;
    }
    void sleep()
    {
        cout<<"animal sleep"<<endl;
    }
    void breathe()
    {
        cout<<"animal breathe"<<endl;
    }   
};

class fish:public animal
{
public:
    fish()//构造函数
    {
        cout<<"fish construct"<<endl;
    }
    ~fish()//析构函数
    {
        cout<<"fish destruct"<<endl;
    }
};

void main
{
    fish fh;
}
//输出结果
//animal construct
//fish construct
//fish destruct
//animal destruct
//没有父亲就没有孩子,fish从animal继承而来,所以在fish类的对象构造前,animal类的要先构造,在析构函数时正好相反。

在子类调用父类中带参数的构造函数:

#include <iostream.h>
class animal
{
public:
    animal(int weight, int height)//构造函数
    {
        cout<<"animal construct"<<endl;
    }
    ~animal()//析构函数
    {
        cout<<"animal destruct"<<endl;
    }
    void eat()
    {
        cout<<"animal eat"<<endl;
    }
    void sleep()
    {
        cout<<"animal sleep"<<endl;
    }
    void breathe()
    {
        cout<<"animal breathe"<<endl;
    }   
};

class fish:public animal
{
public:
    //fish()//如果写成这行,编译会出错,因为找不到animal类不带参数的默认构造函数
    fish():animal(400,300)//这个是正确的
    {
        cout<<"fish construct"<<endl;
    }
    ~fish()//析构函数
    {
        cout<<"fish destruct"<<endl;
    }
};

void main
{
    fish fh;
}

类的继承及类中成员的访问特性,包括三种访问权限:

  • public:定义的成员可以在任何地方被访问
  • protected:定义的成员只能在该类及其子类中访问
  • private:定义的成员只能在该类自身中访问,基类中的private成员不能被子类访问,因此,private成员不能被派生类继承

多重继承:一个类可以从多个基类中派生,定义形式如下:

class 派生类名:访问权限 基类名称,访问权限 基类名称,访问权限 基类名称
{
    ......
};

如B是由C类和D类派生的,形式如下:
class B:public C,public D
{
    ......
};
#include <iostream>

class B1
{
public:
    void output();//成员函数,注意加分号
};

void B1::output()//B1的成员函数,:: 叫做作用域标识符,指明一个函数属或一个数据成员属于哪个类
{
    cout<<"call the class B1"<<endl;
}

class A:public B1 //子类
{
public:
    void show();
};
void A::show()
{
    cout<<"call the class A"<<endl;
}

void main()
{
    A a;
    a.output();
    a.show();
}

虚函数与多态性:虚函数用关键字“virtual”申明,C++的多态性用一句话概括就是:在基类的函数前面加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数,如果是基类,就调用基类的函数。

纯虚函数:将animal类中的breathe函数改成“virtual void breathe()=0; ”则为纯虚函数。纯虚函数先让类具有一个操作名称,而没有操作内容。凡是有纯虚函数的类叫做抽象类,这种类不能声明对象,只是作为基类为派生类服务,在派生类中必须完全实现基类的纯虚函数,否则派生类也成了抽象类,不能实例化对象。

#include <iostream.h>
class animal
{
public:
    void eat()
    {
        cout<<"animal eat"<<endl;
    }
    void sleep()
    {
        cout<<"animal sleep"<<endl;
    }
    virtual void breathe()//如果没有“virtual”关键字,输出结果为animal breathe
    {
        cout<<"animal breathe"<<endl;
    }   
};

class fish:public animal
{
public:
    void breathe()//如果没有“virtual”关键字,输出结果为animal breathe
    {
        cout<<"fish bubble"<<endl;
    }   
};


void fn(animal *pAn)
{
    pAn->breathe();
}//全局函数fn,指向animal类的指针作为fn()函数的参数

void main
{
    animal *pAn;
    fish fh;
    pAn=&fh;
    fn(pAn);
}
//输出结果为fish bubble

函数的覆盖和隐藏:

上面这个代码就称为函数的覆盖(override),构成函数覆盖的条件为:

  • 基类函数必须为虚函数(virtual)
  • 发生覆盖的两个函数分别位于派生类和基类中
  • 函数名称与参数列表必须完全相同

隐藏的情况:(1)派生类的函数和基类函数完全一样(2)派生类的函数和基类函数同名,但参数列表不同。(重载发生在同一个类中)。隐藏发生时如果在派生类的同名函数中想要调用基类的的被隐藏函数可使用“基类名::函数名(参数)”,如Base::fn()

代码示例:

#include <iostream.h>

class Base
{
public:
 virtual void xfn(int i)
 {
  cout<<"Base::xfn(int"<< i<<")"<<endl;
 }
 void yfn(float f)
 {
  cout<<"Base::yfn(float"<< f<<")"<<endl;
 }
 void zfn()
 {
  cout<<"Base::zfn()"<<endl;
 }
};

class Derived:public Base
{
public:
 void xfn(int i)//覆盖了基类的xfn
 {
  cout<<"Derived::xfn(int"<< i<<")"<<endl;
 }
 void yfn(int c)//隐藏了基类的yfn
 {
  cout<<"Derived::yfn(int"<< c<<")"<<endl;
 }
 void zfn()//隐藏了基类的zfn
 {
  cout<<"Derived::zfn()"<<endl;
 }
};

void main()
{
 Derived d;

 Base *pB=&d;
 Derived *pD=&d;

 pB->xfn(5);
 pD->xfn(5);

 pB->yfn(3.14f);
 pD->yfn(3.14f);

 pB->zfn();
 pD->zfn();
}

引用:引用就是一个变量的别名

int a=5;
int &b=a;//用&表示申明一个引用,引用必须在申明时进行初始化
int a=5;
int &b=a;
int c=3;
b=c; //此处是给b赋值,此时,b和a的值都变成了3

引用和指针变量的区别: 

 C++头文件重复包含的问题:如果出现类似以下的错误提示,则可以使用条件预处理指令。

\animal.h(2):error C2011:'animal':'class' type redefinition

条件预处理

/********************* animal.h*******************/
#ifndef ANIMAL_H_H
#define ANIMAL_H_H   //用define定义一个宏

class animal
{
public:
    animal();
    ~animal();
    void eat();
    void sleep();
    virtual void breathe();
};

#endif


/********************* fish.h*******************/
#include "animal.h"
#ifndef FISH_H_H
#define FISH_H_H

class fish
{
public:
    void breathe();
};

#endif

/*******************main.cpp*******************/
#include "animal.h"
#include "fish.h"

//若无条件预处理指令,就会出现上述重定义的提示
//加上后,判断ANIMAL_H_H是否定义,如果没有就定义它,继续执行。
//然后展开fish.h,而fish.h中包含了animal.h,再次展开animal.h,发现ANIMAL_H_H已经定义,于是跳转到#endif

VC++程序编译链接过程:编译(compiling)时,预处理器先对预处理指令进行处理,生成一种临时文件;之后编译器受预处理的输出,将源代码换成包含机器语言指令的目标文件.obj(debug目录下),头文件不参与编译;之后是链接(linking),将.obj文件和C++类库文件一起链接生成可执行文件,exe。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值