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 Private | Public | Public Protected No Access |
Public Protected Private | Protected | Protected Protected No Access |
Public Protected Private | Private | Private 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头文件不参与编译。最后进行链接。