0%

真的是无语,我手一个字一个字的敲的,发布一年后说我抄袭。Lua语言for循环分为两大类:数值for循环、泛型for循环

1.数值for循环

Lua 编程语言中数值for循环语法格式:

1
2
3
for var=exp1,exp2,exp3 do  
<执行体>
end

var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 **”执行体”**。exp3 是可选的,如果不指定,默认为1。

实例:

1
2
3
for i=10,1,-2 do
print(i)
end

以上实例输出结果为:

注意:for的三个表达式在循环开始前一次性求值,以后不再进行求值。

1
2
3
4
5
6
7
function f(x)
print("function")
return x*2
end
for i=1,f(5) do
print(i)
end

以上实例输出结果为:

2.泛型for循环

泛型 for 循环通过一个迭代器函数来遍历所有值,Lua 编程语言中泛型 for 循环语法格式:

1
2
3
4
5
--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end

i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

实例:

1
2
3
4
days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}  
for i,v in ipairs(days) do
print(v)
end

以上实例输出结果为:

多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。

C++ 多态意味着调用成员函数时,据调用函数的对象的类型来执行不同的函数。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
using namespace std;

class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0): width(a), height(b) { }//初始化width, height
int area()
{
cout << "Parent class area :" << endl;
return 0;
}
};
class Rectangle : public Shape {
public:
//Rectangle(int a = 0, int b = 0) :Shape(a, b) { }
Rectangle(int a = 0, int b = 0)
{
width = a;
height = b;
}
int area()
{
cout << "Rectangle class area :" << width * height << endl;
return (width * height);
}
};
class Triangle : public Shape {
public:
Triangle(int a = 0, int b = 0) :Shape(a, b) { }//派生类先调用基类构造函数初始化width, height。然后派生类继承变量
int area()
{
cout << "Triangle class area :" << width * height << endl;
return (width * height / 2);
}
};
// 程序的主函数
int main()
{
Shape *shape;
Rectangle rec(10, 7);
Triangle tri(10, 5);

// 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area();

// 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area();

system("Pause");

return 0;
}

运行结果为

基类的指针可以指向派生类的对象,我们想达到的结果是,分别调用rec对象的area()方法,tri对象的area()方法计算面积。

但调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。

但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:

1
2
3
4
5
6
7
8
9
10
11
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0): width(a), height(b) { }
virtual int area()
{
cout << "Parent class area :" << endl;
return 0;
}
};

运行结果如下:

此时,编译器看的是指针的内容,而不是它的类型。因此,由于 tri 和 rec 类的对象的地址存储在 *shape 中,所以会调用各自的 area() 函数。

正如您所看到的,每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。

虚函数

虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。

想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定

纯虚函数

如果想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。

我们可以把基类中的虚函数 area() 改写如下:

1
2
3
4
5
6
7
8
9
10
11
12
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
  1. = 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数。纯虚函数用来规范派生类的行为,即接口。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。

  2. 虚函数声明如下:

1
2
3
4
5
6
7
8
9
10
11
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0): width(a), height(b) { }
virtual int area();
//{
// cout << "Parent class area :" << endl;
// return 0;
//}
};

虚函数必须实现,如果不实现,编译器将报错,错误提示为

编译器对每个包含虚函数的类创建一个虚函数表VTABLE,表中每一项指向一个虚函数的地址,即VTABLE表可以看成一个函数指针的数组,每个虚函数的入口地址就是这个数组的一个元素。

每个含有虚函数的类都有各自的一张虚函数表VTABLE。每个派生类的VTABLE继承了它各个基类的VTABLE,如果基类VTABLE中包含某一项(虚函数的入口地址),则其派生类的VTABLE中也将包含同样的一项,但是两项的值可能不同。如果派生类中重载了该项对应的虚函数,则派生类VTABLE的该项指向重载后的虚函数,如果派生类中没有对该项对应的虚函数进行重新定义,则使用基类的这个虚函数地址。

在创建含有虚函数的类的对象的时候,编译器会在每个对象的内存布局中增加一个vptr指针项,该指针指向本类的VTABLE。在通过指向基类对象的指针(设为bp)调用一个虚函数时,编译器生成的代码是先获取所指对象的vptr指针,然后调用vptr所指向类的VTABLE中的对应项(具体虚函数的入口地址)。

当基类中没有定义虚函数时,其长度=数据成员长度;派生类长度=自身数据成员长度+基类继承的数据成员长度;

当基类中定义虚函数后,其长度=数据成员长度+虚函数表的地址长度;派生类长度=自身数据成员长度+基类继承的数据成员长度+虚函数表的地址长度。

包含一个虚函数和几个虚函数的类的长度增量为0。含有虚函数的类只是增加了一个指针用于存储虚函数表的首地址。

派生类与基类同名的虚函数在VTABLE中有相同的索引号(或序号)。

函数设计时,可将多个参数通过分隔符连接成为一个参数传入,这样可减少函数的入参数字。函数内部需要对传入的合并参数进行分割,获取需要的参数即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/****************************************************************************

函数名称: iMystrtok

函数功能: 根据sFlg分割sData

*****************************************************************************/

long iMystrtok(string sData, string sFlg, vector<string> &vStr)

{

if (sData.empty())

{

return 0;

}

vStr.clear();

size_t uiOffset = 0, uiPos = 0;

uiPos = sData.find(sFlg, uiOffset);

while (uiPos != string::npos)

{

vStr.push_back(sData.substr(uiOffset, uiPos-uiOffset));

uiOffset = uiPos + sFlg.size();

uiPos = sData.find(sFlg, uiOffset);

}

vStr.push_back(sData.substr(uiOffset, sData.length() - uiOffset));

return 0;

}

例如:

string TestString = string(“2019|hello|world”);

vector sTmp;

iMystrtok(TestString, “|”, sTmp);

cout<<sTmp[0]<<endl;

cout<<sTmp[1]<<endl;

cout<<sTmp[2]<<endl;

输出为:

2019

hello

world

Tab Control是MFC中一个常用的功能,可实现切换界面,将不同功能的控件放置在不同页面中。

1.在工具栏中选择Tab Control控件,将控件大小拉满整个对话框,如图:

2.在对话框类中声明一个 CTabCtrl变量:

CTabCtrl m_tab;

变量用于与Tab Control控件交互,为此要在DoDataExchange函数中加入DDX_Control语句:

DDX_Control(pDX, IDC_TAB1, m_tab); //IDC_TAB1为控件ID

3.选择资源视图插入两个测试页面,右键点击Dialog,选择插入Dialog中,作为Tab Control控件切换的界面,然后将插入的对话框的Border属性设置为None,Style设置为Child,设置后的效果如下图所示:

4.为创建的两个话框建立类,如DlgSS、DlgFinance。添加类的方法:右击对话框界面,在弹出框中选择添加类;

5.在Tab Control控件所在的对话框类的头文件中添加插入的页面对话框的头文件,然后添加以下内容:

1
2
3
4
5
6
7
8
9
int m_FuncTab;

DlgSS m_page0; //没加头文件会报错

DlgFinance m_page1;//没加头文件会报错

std::vector<CDialog*> m_pDialog; //用来保存对话框对象指针,记得添加vector的头文件

afx_msg void OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult);

6.在对话框类的初始化函数中需要把DlogSS和Tab Control关联起来,并保存页面地址,设置初始页面,在OnInitDialog()中添加以下实现代码:

// 为Tab Control增加页面

m_tab.InsertItem(0, _T("测试0"));

m_tab.InsertItem(1, _T("测试1"));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//创建对话框

m_page0.Create(IDD_DIALOG_SS, &m_tab);

m_page1.Create(IDD_DIALOG_Finance, &m_tab);

//设定在Tab内显示的范围

CRect rc;

m_tab.GetClientRect(rc);

rc.top += 20;

rc.bottom -= 0;

rc.left += 0;

rc.right -= 0;

m_page0.MoveWindow(&rc); //设置子对话框尺寸并移动到指定位置

m_page1.MoveWindow(&rc); //设置子对话框尺寸并移动到指定位置
1
2
3
4
5
6
7
8
9
10
11
12
13
//把对话框对象指针保存起来

m_pDialog.push_back(&m_page0);

m_pDialog.push_back(&m_page1);

//显示初始页面

m_pDialog[0]->ShowWindow(SW_SHOW);

//保存当前选择

m_FuncTab = 0;

7.为Tab Control添加消息处理程序,双击Tab Control控件,自动进入消息处理程序代码:

8.运行结果如图:

本文参考的资料有:http://blog.csdn.net/hustspy1990/article/details/5425365

单文档:记事本类程序的标准模式,有菜单栏、工具栏等,只能进行一份文档的操作,即不能同时在同一个应用程序中打开两个文件

多文档:WORD类或浏览器程序的标准模式,可多个窗口显示不同的信息,进行不同的任务,有过个视图环境,可同时操作多个文件。多个文件共享同一菜单栏、工具栏等

对话框:可方便的使用控件,所见即所得的编程,没有菜单栏、工具栏等

怎样看出一个MFC应用程序是基于单文档、多文档还是对话框?

1.运行应用程序观看,对话框一般没有菜单栏、工具栏等,单文档和多文档有,另多文档可产生子窗口,会有一个childframe class

2.从源码中的类观看:

基于对话框—>一般含以下3个类:CAboutDlg、程序名App、程序名Dlg

基于单文档—>一般含以下4个类:CMainFrame、程序名App、程序名Doc、程序名View

基于多文档—>一般含以下5个类:CMainFrame、CChildFrame、程序名App、程序名Doc、程序名View


作者:Lemon萫

来源:CSDN

原文:https://blog.csdn.net/shushuidewoniu/article/details/8631721

版权声明:本文为博主原创文章,转载请附上博文链接!

当你OCX控件的ReleaseMinDependency版时,你得到了下面这个链接错误:

LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main

而Debug版本的编连却顺利通过。

出错原因:

如果你在工程中使用了CRT函数,而这些函数又需要CRT启动代码,就会出现这种链接错误。默认情况下,ReleaseMinDepende配置的Preprocessor definitions中定义了**_ATL_MIN_CRT**,它将CRT启动代码从你的EXE或DLL剔出去了。

背景知识:

ATL支持把一个服务器编连优化成最小尺寸或者依赖性最小。我们可以定义三个预处理器符号来影响服务器的优化。

_ATL_MIN_CRT 服务器不链接标准的C/C++运行库

_ATL_DLL 服务器动态链接工具函数库atl.dll

_ATL_STATIC_REGISTRY 服务器静态链接对组件注册的支持

如果定义了预处理器符号_ATL_MIN_CRT,那么我们的服务器不链接C/C++运行库,并且ATL提供了函数malloc、realloc、new和delete的一个实现。当定义了这个符号时,我们不能调用任何其他的C/C++运行库的函数。否则,就会受到这样的待遇:

LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main

ATL向导生成的ATL工程为所有的Release版本的编连定义了_ATL_MIN_CRT,但是没有为Debug版本定义这个符号。

Debug配置没有定义这三个符号中的任何一个。

RelMinSize配置定义了_ATL_MIN_CRT和_ATL_DLL。

RelMinDependency配置定义了_ATL_MIN_CRT和_ATL_STATIC_REGISTRY。

解决方法:

Project —–> Settings—–> C/C++

在Category中选择General ;

去除**_ATL_MIN_CRT**这个预处理符号;

参考来自:https://blog.csdn.net/richie12/article/details/5799097