【深入浅出MFC】第二章 Win32 基本程序观念

来源:互联网 发布:java三大框架书籍 编辑:程序博客网 时间:2024/06/11 22:37

1.类别及其成员- 谈封装(encapsulation)

member variable(成员变量)和member function(成员函数)

2.基础类别与衍生类别:谈继承(Inheritance)

1.子类拥有父类的所有属性和动作。

2.不同的子类可以继承父类一个相同的动作。

3. 既然所有类别都有display 动作,把它提升到老祖宗CShape 去,然后再继承
之,好吗?不好,因为display 函数应该因不同的形状而动作不同。

4. 如果display 不能提升到基础类别去,我们就不能够以一个for 循环或while
循环干净漂亮地完成下列动作(此种动作模式在对象导向程序方法中重要无
比):
CShape shapes[5];
// 令5 个shapes 各为矩形、四方形、椭圆形、圆形、三角形
for (int i=0; i<5; i++)
{
shapes[i].display;
}

3.this 指针

成员函数有一个隐藏参数,名为this 指针
void setcolor(int color) { m_color = color; }
void setcolor(int color, (CShape*)this) { this->m_color = color; }

4.虚拟函数与多态(Polymorphism)


1.要调用父类别的函数,你必须使用scope resolution operator(::)明白指出。
接下来我要触及对象类型的转换,这关系到指针的运用,更直接关系到为什么需要虚拟
函数。了解它,对于application framework 如MFC 者的运用十分十分重要。
2. 如果你以一个「基础类别之指针」指向「衍生类别之对象」,那么经由该指针
你只能够调用基础类别所定义的函数。
3. 如果你以一个「衍生类别之指针」指向一个「基础类别之对象」,你必须先做
明显的转型动作(explicit cast)。这种作法很危险,不符合真实生活经验,在
程序设计上也会带给程序员困惑。
4. 如果基础类别和衍生类别都定义了「相同名称之成员函数」,那么透过对象指
针调用成员函数时,到底调用到哪一个函数,必须视该指针的原始型别而定,
而不是视指针实际所指之对象的型别而定。

虚拟函数正是为了对「如果你以一个基础类别之指针指向一个衍生类别之对象,那么透
过该指针你就只能够调用基础类别所定义之成员函数」这条规则反其道而行的设计。

如果没有虚拟函数这种东西,你还是可以使用scope resolution operator(::)明白指出调用
哪一个函数,但程序就不再那么优雅与弹性了。

虚拟函数与document 有关的Serialize 函数和与view 有关的OnDraw 函数

多态(Polymorphism)
编译器无法在编译时期判断pEmp->computePay到底是调用哪一个函数,必须在执行时期才能评估之,这称为后期绑定late binding 或动
态绑定dynamic binding。

纯虚拟函数
virtual void display() = 0;virtual void display() = 0;
只要是拥有纯虚拟函数的类别,就是一种抽象类别,它是不能够被具象化(instantiate)的

■  如果你期望衍生类别重新定义一个成员函数,那么你应该在基础类别中把此函
数设为virtual。
■  以单一指令唤起不同函数,这种性质称为Polymorphism,意思是"the ability to
assume many forms",也就是多态。
■  虚拟函数是C++ 语言的Polymorphism 性质以及动态绑定的关键。
77
■ 既然抽象类别中的虚拟函数不打算被调用,我们就不应该定义它,应该把它设
为纯虚拟函数(在函数声明之后加上"=0" 即可)。
■ 我们可以说,拥有纯虚拟函数者为抽象类别(abstract Class),以别于所谓的
具象类别(concrete class)。
■ 抽象类别不能产生出对象实体,但是我们可以拥有指向抽象类别之指针,以便
于操作抽象类别的各个衍生类别。
■ 虚拟函数衍生下去仍为虚拟函数,而且可以省略virtual 关键词。

5.类别与对象大解剖

含有虚函数的类必定有一个指向虚函数表的指针
#include<iostream>using namespace std;class ClassA{public:int m_dataOne;int m_dataTwo;public:void funcOne() { }void funcTwo() { }virtual void vfuncOne() { }virtual void vfuncTwo() { }};class ClassB : public ClassA{public:int m_dataThree;public:void funcTwo() { }virtual void vfuncOne() { }};class ClassC : public ClassB{public:int m_dataOne;int m_dataFour;public:void funcTwo() { }virtual void vfuncOne() { }};void main(){std::cout<<sizeof(ClassA)<<std::endl;std::cout<<sizeof(ClassB)<<std::endl;std::cout<<sizeof(ClassC)<<std::endl;ClassA a;ClassB b;ClassC c;b.m_dataOne = 1;b.m_dataTwo = 2;b.m_dataThree = 3;c.m_dataOne = 1;c.m_dataTwo = 2;c.m_dataThree = 3;c.m_dataFour = 4;c.ClassA::m_dataOne = 111;cout<<b.m_dataOne<<endl;cout<<b.m_dataTwo<<endl;cout<<b.m_dataThree<<endl;cout<<c.m_dataOne<<endl;cout<<c.m_dataTwo<<endl;cout<<c.m_dataThree<<endl;cout<<c.m_dataFour<<endl;cout<<c.ClassA::m_dataOne<<endl;cout<<&b<<endl;cout<<&b.m_dataOne<<endl;cout<<&b.m_dataTwo<<endl;cout<<&b.m_dataThree<<endl;cout<<&c<<endl;cout<<&c.m_dataOne<<endl;cout<<&c.m_dataTwo<<endl;cout<<&c.m_dataThree<<endl;cout<<&c.m_dataFour<<endl;cout<<&c.ClassA::m_dataOne<<endl;system("pause");}

6.Object slicing  与虚拟函数

#include <iostream>using namespace std;class CObject{public:virtual void Serialize(){cout<<"COject::Serialize() \n\n";}};class CDocument : public CObject{public:int m_dataOne;virtual void Serialize(){cout<<"CDocument::Serialize() \n\n";}void func(){cout<<"CDocument::func()"<<endl;Serialize();}};class CMyDoc : public CDocument{public:int m_dataTwo;virtual void Serialize(){cout<<"CMyDoc::Serialize() \n\n";}};void main(){CMyDoc mydoc;CMyDoc* pmydoc = new CMyDoc;cout<<"#1 testing"<<endl;mydoc.func();cout<<"#2 testing"<<endl;((CDocument*)(&mydoc))->func();cout<<"#3 testing"<<endl;pmydoc->func();cout<<"# 4testing"<<endl;((CDocument)mydoc).func();system("pause");}


经过data slicing 把mydoc变成了一个完完全全的CDocument对象了。
其中(CDocument)mydoc强制转换将会把对象的内容分割。

7.静态成员(函数和变量)

static double m_rate;
static成员变量不是对象的一部分,而是类的一部分,所以程序还没有诞生对象的时候就由此成员变量了。
static成员变量不要安排在构造函数中,也不要安排在头文件中,因为它可能被执行很多次。
double Saving::m_rate = 0.0075
Saving::m_rate = 0.0075 //需把m——rate改为public。

如果希望在产生object之前就存取class中的private static成员变量,就设计一个static成员函数。
static void setRate(double newRate){m_rate = newRate;}

8.C++程序的生与死:构造与析构函数

1.new 不但配置对象所需的内存空间,而且会引发构造函数的执行。
2. 全局对象:程序开始就构造函数,程序结束前析构。
   静态对象:程序诞生时构造函数执行,程序结束前析构但是比全局对象早。
   new出来的局部对象:诞生时构造函数执行,delete时析构。
   局部对象:执行到的时候构造,局部函数结束时析构。
原创粉丝点击