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

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时析构。
   局部对象:执行到的时候构造,局部函数结束时析构。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值