VS2010 C++ MFC框架学习笔记4 - C++面向对象编程基础2

VS2010 C++ MFC框架学习笔记4 - C++面向对象编程基础2

跟着教材《Visual C++ 2010 MFC 编程入门》.pdf 学习了2周,感觉有些基础的概念不太清楚,所以找出网易学堂的VC++课程进行学习http://tech.163.com/special/0009159F/vc.html

===========================================

[第二课 C++经典语法与应用 类的编写与应用]

===========================================

构造函数:采用类的方式来保证它的唯一性,取个类名,没有返回值,对类里的变量进行初始化。

析构函数:回收内存,没有返回,没有参数。

例:

1. #include<iostream>
2. using namespace std;
3. class Point{
4. public:
5. int x;
6. int y;
7. Point(){	//构造函数,同,类名
8. x = 0;
9. y = 0;
10. }
11. 
12. Point(int a, int b){ //构造函数,带参
13. x = a; y = b;
14. }
15. 
16. ~Point(){	//析构函数,取反符号+类名
17. }
18. 
19. void output(){
20. cout<<x<<endl<<y<<endl;
21. }
22. void output(int x, int y){
23. this->x = x;	//this point, 指向对象
24. this->y = y;
25. }
26. };
27. 
28. void main(){
29. Point pt(3,3);
30. pt.output(5,5);
31. pt.output();
32. }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

上例中,出现了两个Point()构造函数,这种情况称为函数的重载:函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。参考:http://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html

this指针是一个隐含的,指向对象本身,代表对象地址的指针;一个类所有的对象调用的成员函数都是同一代码段,如何区分不同对象但是同一类下的成员函数的执行呢?其实,成员函数除了接受参数外,还接受了一个对象的地址,这个地址被一个隐含的形参this指针所获取,等同于执行 this = &pt. 所有对数据成员的访问都隐含地被加上前缀this->

继承:

====================public; protected; private在继承中,对method的保护权限区别:  》public    是外部Y访问,子类Y访问  》protected     是外部N访问,子类Y访问  》private    是外部N访问,子类N访问如:

1. #include<iostream>
2. using namespace std;
3. 
4. class Animal{
5. public:
6. void eat(){
7. cout<<"animal eat"<<endl;
8. }
9. protected:
10. void sleep(){
11. cout<<"animal sleep"<<endl;
12. }
13. private:
14. void breathe(){
15. cout<<"animal breathe"<<endl;
16. }
17. };
18. 
19. class Fish : public Animal{ //子类的继承特性:这里是public式继承
20. void test(){
21. sleep(); //protected,子类中可以访问
22. //breathe();//private,子类都不能access
23. }
24. };
25. 
26. void main(){
27. Animal an;
28. an.eat();
29. Fish fh;
30. //fh.sleep();//protected, cannot access
31. }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

这里有个继承的权限叠加后,对method的最终对外访问权限的判定问题:

基类method的权限:   子类的继承特性:   最终对外访问特性:

基类method权限类继承特性子类的访问特性
Public Protected PrivatePublicPublic Protected No Access
Public Protected PrivateProtectedProtected Protected No Access
Public Protected PrivatePrivatePrivate Private No Access

构造函数的访问顺序
父类{
    父类的构造函数(){
        指令1;
    }
    ~父类的构造函数(){
        指令2;
    }
    
}

子类:public 父类{    //继承
    子类的构造函数(){
        指令3;
    }
    ~子类的构造函数(){
        指令4;
    }
}

main(){
    子类.子类obj;
}

====执行结果:====
        指令1;
        指令3;
        指令4;
        指令2;


如果父类的构造函数带参数,而子类不带,则子构造函数:
  Fish():Animal(400,300){
}

========================

完整代码:

1. #include<iostream>
2. using namespace std;
3. 
4. class Animal{
5. public:
6. Animal(int x, int y){
7. cout << "animal construct"<<endl;
8. cout << x <<endl;
9. cout << y <<endl;
10. }
11. 
12. void eat(){
13. cout<<"animal eat"<<endl;
14. }
15. protected:
16. void sleep(){
17. cout<<"animal sleep"<<endl;
18. }
19. private:
20. void breathe(){
21. cout<<"animal breathe"<<endl;
22. }
23. };
24. 
25. class Fish : public Animal{
26. public:
27. Fish():Animal(300,400),a(11){
28. cout<<"fish construct"<<endl;
29. cout<<a<<endl;
30. }
31. 
32. void test(){
33. sleep(); //protected,子类中可以访问
34. //breathe();//private,子类都不能access
35. }
36. private:
37. const int a;
38. };
39. 
40. void main(){
41. //Animal an;
42. //an.eat();
43. Fish fh;
44. //fh.sleep();//protected, cannot access
45. 
46. getchar();
47. }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

函数的覆盖:

发生在父类和子类之间的,父类下有个method_name(){},子类下也有个同名method_name(){},则子类的obj优先执行子类的函数/method

但是,如果又要用父类的method,则使用两个冒号来作为作用域标识符,例:

1. class Fish : public Animal{
2. public:
3. Fish(){
4. }
5. void breathe(){
6. Animal::breathe(); //此处就是调父类的breathe()来
7. cout<<"fish bubble"<<endl;
8. }
9. };

C++继承的多态性:

1. void fn(Animal *pAn){  //有一个全局函数,输入Animal指针,找指针下的breathe()方法进行执行。
2. pAn->breathe();
3. }
4. 
5. void main(){
6. Fish fh;    //obj Declare
7. Animal *pAn;    //pointer Declare
8. pAn = &fh;    //赋值
9. fh(pAn);    //调用
10. }
11. //因为Fish是Animal的子类,
12. //目测会调用Fish的breathe()函数来执行,
13. //但是却执行了Animal类下的breathe()

原因就是Fish和Animal是共用的一个内存起始地址。如下:

  —————

   |  Animal  |

  —————

   |   Fish     |

  ————— 如果要根据不同的类型(Animal or Fish)来调用不同类(Animal or Fish)下的函数,则可利用C++的多态性,在Animal的breathe()前加个virtual,将之定义为“虚函数”,让C++编译器作一个 late binding迟绑定。就可以了:

    virtual void breathe(){
        cout<<"Animal breathe"<<endl;
    }

此时,再运行 fn(pAn) ,如果子类中有 breathe,则就会调用子类Fish中的breathe,如果没有,再调用Animal中的breathe

纯虚函数:

让父类只有操作名称,而没有具体的操作内容;让派生类在继承时候再具体地给出它的定义。

Animal 下:  virtual void breathe() = 0;
Fish 下:    void breathe(){ cout <<"fish bubble..."<<endl ;}

在不确定这种行为具体表现形式,而这种行为又是必须的,就可以在基类中以这种纯虚函数来。

C++中的引用:

把工程文件按.h & .cpp来管理:
.h  文件用于类的声明;
.cpp文件用于类的定义。
这里,Fish是继承于Animal的类,则include"“的顺序要注意:

一个进一步的模型是:

也就是说,在main.cpp中include了Animal.h & Fish.h;     在Fish.h & Animal.cpp中,include"Animal.h” ;    在Fish.cpp中 include“Fish.h”

这里会有一个错误:因为main.cpp引用了Animal.h,同时main.cpp引用了Fish.h,而Fish.h再次引用了Animal.h,所以会报Animal.h中的类被重复定义。怎么办呢?使用预编译命令: #ifndef #def #endif

使用预编译命令

main.cpp引用了Animal.h,然后main.cpp引用了Fish.h,而Fish.h再次引用了Animal.h,所以会报Animal.h中的类被重复定义。怎么办呢?

使用预编译命令: #ifndef #def #endif
1. //File: Animal.h
2. //Declare the Animal class and the functions
3. //
4. #ifndef ANIMAL_H_H //用预编译指令符防止类的重复编译错误: if not define
5. #define ANIMAL_H_H //用预编译指令符防止类的重复编译错误: define
6. class Animal{
7. public:
8. Animal(int height, int weight);//构造函数
9. void eat();//
10. void sleep();//
11. virtual void breathe();//virtual
12. };
13. #endif  //用预编译指令符防止类的重复编译错误: end if

VC++编译链接过程

先对cpp文件进行编译,编程成obj文件,h头文件不参与编译。最后进行链接。

Published At
comments powered by Disqus