打印
[菜农群课笔记]

20111223群课笔记

[复制链接]
1813|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xyz549040622|  楼主 | 2011-12-27 11:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xyz549040622 于 2011-12-28 09:01 编辑

20111223_.pdf (285.8 KB)

John Lee(1513562323) 20:28:41
今天我们来讨论一下关于使用C++ 临时对象缓冲技术访问特殊功能寄存器方法的内部实现。
John Lee(1513562323) 20:29:34
首先我们需要了解SFR是如何定义的,我们选取UARTBAUD寄存器作为讨论的对象,
John Lee(1513562323) 20:29:57
这是因为BAUD寄存器中,不仅有单个位的位域,还有多个位的位域,相对其它只含有单个位域的寄存器,BAUD寄存器更能说明问题。
John Lee(1513562323) 20:30:38
下面是uart外设的结构定义,为了清晰起见,我们只保留BAUD寄存器的成员定义,略去了其它无关紧要的定义。
John Lee(1513562323) 20:31:05
struct uart_t {
...
volatile sfr_t<baud_t> BAUD;
...
};
日期:2011/12/23
John Lee(1513562323) 20:31:34
我们可以看到BAUD成员的类型是volatile sfr_t<baud_t>,其中有一个volatile修饰符,我们暂且不表。
John Lee(1513562323) 20:32:00
那么sft_t<baud_t>是什么东西?
John Lee(1513562323) 20:32:11
这只不过是 C++ 的模板类。大家不要晕,不要把模板想得很高深,把自己吓倒了。
John Lee(1513562323) 20:32:49
模板类,就像是带参数的宏定义,只不过普通的宏定义是由 C/C++ 预处理程序处理了,而模板,则是由编译器自己处理的。
John Lee(1513562323) 20:33:32
我们知道,预处理程序对宏的参数的语**确性不会做任何检查,只是简单地替换而已,最后的正确性是由编译器来检查的。
皇星客栈-Linux(769181464)20:34:11
恩恩
John Lee(1513562323) 20:34:16
而模板类的参数,就有一些语法要求了,参数只能有两种,第1种是“类型”,第2种是“常数值”。
John Lee(1513562323) 20:34:45
例如:
template<typename T, int N>
class foo { ... };


John Lee(1513562323) 20:35:26
其中的 T 就是一种类型,N 是一个常数,注意,这里的 T N 都是“形参”,在模板类定义时,只具有抽象意义。
John Lee(1513562323) 20:36:18
当我们创建模板类的实例时,必须给出模板类的参数,就像使用宏一样要给出宏的参数。
John Lee(1513562323) 20:36:50
例如:
foo<char, 2> foo1;
雁塔菜农(1270688699)20:36:52

John Lee(1513562323) 20:37:30
char就是一个具体类型了,用来作为“实参”代替“形参”T,常数 2 也是用来代替 N 的。
John Lee(1513562323) 20:38:00
宏和模板的区别还有一点,模板允许递归,而宏不允许。
John Lee(1513562323) 20:40:09
通过给模板类不同的参数,我们就可以“生成”若干不同的新类型,这些类型都有类似的行为(成员函数)。


John Lee(1513562323) 20:41:02
模板就简单地介绍到这里了,大家可能还是觉得很抽象,下面我们就回过头继续讲寄存器的访问,
John Lee(1513562323) 20:41:49
里面涉及了一些模板的操作,我们在讲的过程中,大家就可以继续加深对模板的认识。
皇星客栈-Linux(769181464)20:43:05
恩恩
John Lee(1513562323) 20:43:30
我们先找到sfr_t模板类的定义:
template<typename SFR>
class sfr_t { // Special Function Register
public:
__INLINE operator decltype(SFR::val)() {return val; }
__INLINE sfr_t<SFR> operator =(SFR v){ val = v.val; return *this; }
__INLINE decltype(SFR::val) operator=(decltype(SFR::val) v) { val = v; return v; }
__INLINE SFR operator ()() { returnSFR(val); }
__INLINE SFR operator ()(decltype(SFR::val)v) { return SFR(val, v); }
volatile decltype(SFR::val) val;
};
我们也略去了其中不是关键的部分。
John Lee(1513562323) 20:44:52
当我们定义uart_t的成员BAUD时,使用了baud_t这个类型作为sfr_t模板的参数,
John Lee(1513562323) 20:45:47
我们可以把sfr_t的形参SFR,用手工替换成baud_t,得到如下结果:
John Lee(1513562323) 20:46:18
class sft_t<baud_t> { // SpecialFunction Register
public:
__INLINE operator decltype(baud_t::val)() {return val; }
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
__INLINE decltype(baud_t::val) operator=(decltype(baud_t::val) v) { val = v; return v; }
__INLINE baud_t operator ()() { returnbaud_t(val); }
__INLINE baud_t operator()(decltype(baud_t::val) v) { return baud_t(val, v); }
volatile decltype(baud_t::val) val;
};


John Lee(1513562323) 20:47:13
在这里,我们第一个看不明白的地方可能是decltype(baud_t::val)
murex(344582199) 20:47:27

寒雨(251539157)20:47:33
是的
John Lee(1513562323) 20:47:54
这仅仅是一个“类型”,只不过这个类型不是定死的,而是根据baud_t::val的类型来动态定义的一个类型,
John Lee(1513562323) 20:48:24
decltype C++11 的关键字,括号里是一个已存在的类型表达式,decltype可以取得其类型,然后用这个类型去定义新的变量等等。
murex(344582199) 20:49:04
这个不错,牛,还有这种用法
murex(344582199) 20:49:08
c++强悍
John Lee(1513562323) 20:49:25
baud_t::val,从字面意思可以看出,有一个名叫baud_t的类,里面有一个叫val的成员。
日期:2011/12/23
寒雨(251539157)20:49:45

John Lee(1513562323) 20:50:19
如果baud_t::val的类型是char,那么:
__INLINE operator decltype(baud_t::val)() {return val; }
就变成了:
__INLINE operator char() { return val; }
John Lee(1513562323) 20:52:01
现在是不是清楚一些了?这实际上是一个“类型转换”函数。
murex(344582199) 20:52:11
嗯,清楚了
John Lee(1513562323) 20:53:27
可以通过这个operatorchar()函数,把sfr_t<baud_t>类对象,转换为char类型数据。
寒雨(251539157)20:53:52

John Lee(1513562323) 20:54:18
如果没有定义这个函数,编译器就不知道如何转换。
murex(344582199) 20:54:49
那是的了
John Lee(1513562323) 20:55:47
例如:
sfr_t<baud_t> baud_data;
char ch_data = baud_data;


John Lee(1513562323) 20:57:09
C/C++的隐含转换规则,是没有用户类型转换的。
John Lee(1513562323) 20:58:09
我们定义了这样一个转换函数,就是为编译器定义了一个转换规则。
John Lee(1513562323) 20:59:06
下面,我们继续追踪,去看看baud_t是什么样的:
John Lee(1513562323) 20:59:22
union baud_t { // Baud Rate DividerRegister (UA_BAUD)
__SFR(baud_t, uint32_t, 0)
sfb_t<baud_t, uint32_t, 0, 16> BRD;
sfb_t<baud_t, uint32_t, 24, 4>DIVIDER_X;
sfb_t<baud_t, uint32_t, 28, 1>DIV_X_ONE;
sfb_t<baud_t, uint32_t, 29, 1>DIV_X_EN;
};


John Lee(1513562323) 20:59:48
baud_t是一个“union”类型,有一个宏__SFR,和4个成员。
John Lee(1513562323) 21:00:03
继续追踪__SFR
John Lee(1513562323) 21:00:58
看代码就是要学会追踪,一步一步深入,但不要迷路,要做好路标,一旦某条路追到了底后,能找到回来的路。
皇星客栈-Linux(769181464)21:01:16
恩恩
John Lee(1513562323) 21:02:05
追踪代码,就像是钻迷宫,要一条路一条路的钻。
murex(344582199) 21:02:22
找到根为止
John Lee(1513562323) 21:03:13
__SFR宏是这样的:
#define __SFR(SFR, TYPE, WRITE) \
__INLINE SFR(TYPE volatile& r) :ref(r), val(r), changed(0) { } \
__INLINE SFR(TYPE volatile& r, TYPE v): ref(r), val(v), changed((TYPE)(-1)) { } \
__INLINE ~SFR() { apply(); } \
__INLINE SFR& apply() \
{ \
if (changed != 0) { \
ref = val; \
changed = 0; \
} \
return *this; \
} \
struct { \
volatile TYPE& ref; \
TYPE val; \
TYPE changed; \
};


John Lee(1513562323) 21:03:49
现在我们把它展开到unionbaud_t中:
John Lee(1513562323) 21:04:34
union baud_t { // Baud Rate Divider Register(UA_BAUD)
__INLINE baud_t(uint32_t volatile& r) :ref(r), val(r), changed(0) { } \
__INLINE baud_t(uint32_t volatile& r,uint32_t v) : ref(r), val(v), changed((uint32_t)(-1)) { } \
__INLINE ~baud_t() { apply(); } \
__INLINE baud_t& apply() \
{ \
if (changed != 0) { \
ref = val; \
changed = 0; \
} \
return *this; \
} \
struct { \
volatile uint32_t& ref; \
uint32_t val; \
uint32_t changed; \
};


sfb_t<baud_t, uint32_t, 0, 16> BRD;
sfb_t<baud_t, uint32_t, 24, 4>DIVIDER_X;
sfb_t<baud_t, uint32_t, 28, 1>DIV_X_ONE;
sfb_t<baud_t, uint32_t, 29, 1>DIV_X_EN;
};


John Lee(1513562323) 21:05:40
好了,我们终于看到了baud_t::val,它的类型是uint32_t
murex(344582199) 21:05:53

John Lee(1513562323) 21:06:55
那么我们先回过头来,把sft_t<baud_t>类中的decltype(baud_t::val),全部替换为uint32_t
John Lee(1513562323) 21:07:55
得到结果如下:
class sft_t<baud_t> { // SpecialFunction Register
public:
__INLINE operator uint32_t() { return val;}
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
__INLINE uint32_t operator =(uint32_t v) {val = v; return v; }
__INLINE baud_t operator ()() { returnbaud_t(val); }
__INLINE baud_t operator ()(uint32_t v) {return baud_t(val, v); }
volatile uint32_t val;
};


John Lee(1513562323) 21:08:51
现在,sfr_t<baud_t>类就是最终的样子了。
John Lee(1513562323) 21:09:43
我简单讲解一下sfr_t<baud_t>类的成员。
murex(344582199) 21:09:55

John Lee(1513562323) 21:09:56
1__INLINE operator uint32_t() { return val; }
日期:2011/12/23
John Lee(1513562323) 21:11:41
这是“类型转换”函数,可以把sfr_t<baud_t>类的对象,转换为uint32_t
寒雨(251539157)21:12:43
这函数好用
John Lee(1513562323) 21:13:23
现在提个问,sfr_t<baud_t>类的对象(也叫实例)是哪个?


John Lee(1513562323) 21:13:43
看谁先中奖。
murex(344582199) 21:14:31
_INLINE baud_t operator ()(uint32_t v) {return baud_t(val, v); }


John Lee(1513562323) 21:15:24
暂停5分钟,大家快找答案。5分钟后继续。
潜龙思瑞(373744463)21:16:26
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }


murex(344582199) 21:16:58
嗯,应该是这个的了
John Lee(1513562323) 21:17:24
错,继续找
难民人(95714627)21:18:44


难民人(95714627)21:18:49
z这个
难民人(95714627)21:18:53
类的对象
皇星客栈-Linux(769181464)21:19:22

__INLINEbaud_t operator ()(uint32_t v) { return baud_t(val, v); }
难民人(95714627)21:19:33
对吗? 李老师
John Lee(1513562323) 21:19:38

murex(344582199) 21:19:58
赶紧说啊,总共就没几个了
murex(344582199) 21:20:00
哈哈
寒雨(251539157)21:20:39
class sft_t<baud_t> { // SpecialFunction Register


潜龙思瑞(373744463)21:20:48
volatile decltype(baud_t::val) val;


consif(593049297) 21:20:53
union baud_t { // Baud Rate DividerRegister (UA_BAUD)


难民人(95714627)21:21:16
__INLINE operator uint32_t()
__INLINE baud_t operator ()()
__INLINE baud_t operator ()(uint32_t v)
难民人(95714627)21:21:22
这个就对了
John Lee(1513562323) 21:21:40
sfr_t<baud_t>类的对象!!显然是个数据嘛,咋个都去找函数?
难民人(95714627)21:21:53


寒雨(251539157)21:22:04
我对了一半
寒雨(251539157)21:22:06
呵呵
寒雨(251539157)21:22:17
sft_t<baud_t>
潜龙思瑞(373744463)21:22:49
实例不就是函数么
John Lee(1513562323) 21:23:08
sfr_t<baud_t>类!!!这个是“类型”,就像intchar等一样。

相关帖子

沙发
xyz549040622|  楼主 | 2011-12-27 11:18 | 只看该作者
本帖最后由 xyz549040622 于 2011-12-27 11:20 编辑

寒雨(251539157)21:23:10
是啊
日期:2011/12/23
雁塔菜农(1270688699)21:23:16
对的送**蛋
寒雨(251539157)21:23:31
都没对的
难民人(95714627)21:24:08
baud_t(val, v);
难民人(95714627)21:24:46
operator 就这个了
John Lee(1513562323) 21:25:09
,一个都答不上啊,真悲剧。
murex(344582199) 21:26:32
公布吧
潜龙思瑞(373744463)21:26:36
sfr_t<baud_t> baud_data;
char ch_data = baud_data;


tao560532(578645627) 21:27:22
太难了
tao560532(578645627) 21:27:23

John Lee(1513562323) 21:27:26
潜龙思瑞(373744463)
21:26:35
sfr_t<baud_t> baud_data;
char ch_data = baud_data;
------------
靠谱了,但这个只是我举例说明。
潜龙思瑞(373744463)21:27:58
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
潜龙思瑞(373744463)21:29:25
volatile uint32_t val;
难民人(95714627)21:29:29
volatile decltype(baud_t::val) val;


John Lee(1513562323) 21:29:45
嘿,qq消息记录怎么把<>都丢掉了?
难民人(95714627)21:30:01
说我吗?
难民人(95714627)21:30:58
struct uart_t {
...
volatile sfr_t<baud_t> BAUD;
...
};struct uart_t {
...
volatile sfr_t<baud_t> BAUD;
...
};




John Lee(1513562323) 21:32:43
这个structuart_t的结构,我在群课开始就给出了啊。
难民人(95714627)21:33:04
,前面的没听到。 继续讲课
John Lee(1513562323) 21:33:05
下面是uart外设的结构定义,为了清晰起见,我们只保留BAUD寄存器的成员定义,略去了其它无关紧要的定义。
struct uart_t {
...
volatile sfr_t<baud_t> BAUD; // BaudRate Divider Register (UA_BAUD)
...
};
日期:2011/12/23
John Lee(1513562323) 21:33:27
大家都忘了,这么快?
寒雨(251539157)21:33:27
我也是
难民人(95714627)21:33:55
要是能听到你的声音就更好了
难民人(95714627)21:34:07
老师继续讲课吧!
潜龙思瑞(373744463)21:34:13
我来晚了,我的消息没有哟
John Lee(1513562323) 21:35:01
继续
John Lee(1513562323) 21:36:47
我们可以看到,这个函数直接返回了数据成员val,意思是如果要把BAUD赋值给一个uint32_t数据,编译器会把sfr_t<baud_t>::val成员作为右值。
John Lee(1513562323) 21:37:49
uint32_t baud = UART0.BAUD;
John Lee(1513562323) 21:38:24
2__INLINE sfr_t<baud_t> operator =(baud_t v) { val = v.val;return *this; }
John Lee(1513562323) 21:39:53
这个是“赋值操作符”函数,用于把另一个baud_t对象,赋值到本对象。
John Lee(1513562323) 21:40:48
3__INLINE uint32_t operator =(uint32_t v) { val = v; return v; }
John Lee(1513562323) 21:41:45
这个也是“赋值操作符”函数,重载的,用于把一个uint32_t 类型的数据赋值到BAUD sfr_t<baud_t>”。
John Lee(1513562323) 21:42:07
UART0.BAUD = 20;
John Lee(1513562323) 21:42:41
就依赖这个“赋值操作符”函数。
John Lee(1513562323) 21:43:09
4__INLINE baud_t operator ()() { return baud_t(val); }
John Lee(1513562323) 21:44:46
这个是“()”操作符函数,当我们使用UART0.BAUD()这种形式的表达式,编译器就会使用()操作符函数。
John Lee(1513562323) 21:45:19
5__INLINE baud_t operator ()(uint32_t v) { return baud_t(val, v); }
John Lee(1513562323) 21:46:23
这个也是重载的“()”操作符函数,上面那个()是空的,而这个有uint32_t v形参。
John Lee(1513562323) 21:47:33
当我们使用UART0.BAUD(数据) 这种形式的表达式,编译器就会使用括号操作符函数。


John Lee(1513562323) 21:48:59
这两个“括号”操作符函数,返回类型都是baud_t类型。
John Lee(1513562323) 21:51:06
意思是返回一个baud_t类型的对象,在C++中,当某个函数返回了一个对象,注意,不是指针,不是引用,那么这个对象就是一个“临时对象”。
John Lee(1513562323) 21:52:29
我们再深入讨论一下
John Lee(1513562323) 21:53:25
返回类型是一个普通类型的函数,比如:int foo();
John Lee(1513562323) 21:53:49
返回的int型数据在什么地方?
John Lee(1513562323) 21:54:22
C/C++调用协议,这个返回值一般在寄存器中。
John Lee(1513562323) 21:54:30
CPU寄存器
John Lee(1513562323) 21:55:26
这个数据,按面向对象的观点来看,其实也是一个对象,一个int类型的对象。
John Lee(1513562323) 21:55:49
只不过这个int类型,是编译器的内置类型,不需我们定义的。
John Lee(1513562323) 21:56:42
当我们在程序中使用了:intdata = foo();
John Lee(1513562323) 21:58:51
在编译器看来,foo()首先产生了一个int型的“临时对象”,放在CPU寄存器中,然后通过赋值操作符函数(也是编译内置的),把这个“临时对象”,copy到了data变量中。
日期:2011/12/23
John Lee(1513562323) 21:59:24
如果我们这样写:
foo();
murex(344582199) 21:59:58
对象运作后自动析构了
John Lee(1513562323) 22:02:53
按调用协议,foo()函数同样要生成int临时对象,但这个临时对象却没有使用。按系统默认的析构函数,这个临时对象就简单地丢弃了。
John Lee(1513562323) 22:03:52
上面的int data =foo(); 临时对象在copy到了data变量后,也丢弃了。
John Lee(1513562323) 22:05:36
编译器对于内置数据类型(char,int, float),析构的方法就是什么都不做。
John Lee(1513562323) 22:07:21
而对于用户定义类型(struct,class等),如果其中定义了析构函数,那么编译器在析构这种对象时,会调用析构函数,如果没有定义,那么编译器也是什么都不做。
John Lee(1513562323) 22:09:42
今天就讲到这里吧,估计晕的不在少数。
可乐小子(479357804)22:09:56
我已经晕了
John Lee(1513562323) 22:09:58
有问题随时问我。
murex(344582199) 22:10:02
每次都是晕在那几个()()
可乐小子(479357804)22:10:11
晕好久看了..
John Lee(1513562323) 22:10:27
下次继续讲()().
潜龙思瑞(373744463)22:10:30
恩,我晕
murex(344582199) 22:10:34


murex(344582199) 22:10:45
好,欢迎老师再晕我们几次
murex(344582199) 22:10:50
估计就不太会晕了
John Lee(1513562323) 22:11:05
晕,就要提问。
John Lee(1513562323) 22:11:17
不能总是晕。
batsong@21IC(6335473) 22:11:20
今天来晚了啊
可乐小子(479357804)22:11:33
老师,我对c++的了解仅限于类,寒假里要好好学习c++.否则俺听不懂啊..
可乐小子(479357804)22:12:02
老师,你推荐我重点学习c++的哪一块啊??
John Lee(1513562323) 22:12:06
好,仔细看看书,有问题就来问。
潜龙思瑞(373744463)22:12:13
我要看看明天的整理才能问出问题来
潜龙思瑞(373744463)22:12:18
我也来晚了
潜龙思瑞(373744463)22:12:37
好,谢谢老师李
John Lee(1513562323) 22:12:57
嗯,今天讲的内容,应该比较有条理,笔记容易整理。
可乐小子(479357804)22:13:02
老师,你推荐我重点学习c++的哪一块啊??c++没接触过..


murex(344582199) 22:13:08
是的
batsong@21IC(6335473) 22:13:16
我问一个,这个语法怎么理解?
MainWindow::MainWindow(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::MainWindow)
{

ui->setupUi(this);
}
John Lee(1513562323) 22:13:34
那一句?
日期:2011/12/23
murex(344582199) 22:13:36
好好再看两边内容,再来问问题
batsong@21IC(6335473) 22:13:40
,

ui(new Ui::MainWindow)


John Lee(1513562323) 22:14:35
uiMainWindow的基类或成员。
难民人(95714627)22:15:03
以后笔记在那里下?
John Lee(1513562323) 22:15:15
Ui::MainWindow是一个类型
batsong@21IC(6335473) 22:15:25
是的,uiMainWindow私有成员,这个语句放在这能初始化?
John Lee(1513562323) 22:15:37
可以啊
lxyppc(19148022) 22:15:38
MainWindow::MainWindow(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::MainWindow)
{

ui->setupUi(this);
}
以聚合方式使用UI文件生成UI初始化代码
batsong@21IC(6335473) 22:15:49
而且变量初始化能直接在括号里面写?
lxyppc(19148022) 22:16:00
Qt中有两种方式使用,多继承和聚合
John Lee(1513562323) 22:16:11
构造函数的初始化列表中,除了能放基类的初始化外,还可以放成员的初始化。
lxyppc(19148022) 22:16:34
其实你把setupUi代码找出来就知道里面具体做了什么工作
batsong@21IC(6335473) 22:16:39
ui = new Ui::MainWindow
那应该是这种语法啊
batsong@21IC(6335473) 22:16:51
我都看了啊
batsong@21IC(6335473) 22:16:54
这没懂
John Lee(1513562323) 22:17:03
class foo {

foo();

int data;
};


foo::foo()
: data(2)
{
}
batsong@21IC(6335473) 22:17:21
为啥不直接在构造函数内部写
ui = new Ui::MainWindow
lxyppc(19148022) 22:17:22
Ui是一个命名空间
John Lee(1513562323) 22:18:20
ui如果是const成员,就必须在初始化列表中进行初始化。
John Lee(1513562323) 22:19:11
如果不是const的,那么在初始化列表或函数体中初始化都可以。
雁塔菜农(1270688699)22:19:33
很重要
batsong@21IC(6335473) 22:20:10
空间都是分配在堆区?

使用特权

评论回复
板凳
xyz549040622|  楼主 | 2011-12-27 11:21 | 只看该作者
John Lee(1513562323) 22:20:38

不见得,new也是可以重载的。

batsong@21IC(6335473) 22:21:13

关键字也能重载

John Lee(1513562323) 22:21:49

如果Ui::MainWindow(这是一个类吧?)中重载了new,那么 new Ui::MainWindow就要按重载的new来操作。

lxyppc(19148022) 22:22:07

关键字和运算符重载也是C++难懂的原因之一

batsong@21IC(6335473) 22:22:45

我以前看的书上没看到关键字重载

batsong@21IC(6335473) 22:22:47

新特性?

lxyppc(19148022) 22:23:05

new是一种运算符

John Lee(1513562323) 22:23:59

class foo {

    operator new (size_t size) { ... };

    ...

}



foo* p = new foo;

日期:2011/12/23

John Lee(1513562323) 22:24:39

这个new foo,就要调用foo::new来分配。这就可以用户定制分配方法。

batsong@21IC(6335473) 22:25:22

没有一个对象来调用new啊

John Lee(1513562323) 22:26:43

这个特殊语法,编译器首先看要new的类(foo)中有没有重载new,如果有,就用之,否则,就用全局的new.

batsong@21IC(6335473) 22:26:55



lxyppc(19148022) 22:27:31

这个地方这样写

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

}

和这样写

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui = new Ui::MainWindow;

    ui->setupUi(this);

}

是等效的,Qt中这样使用new没有特别的含义

lxyppc(19148022) 22:30:48

但是为什么Qt要用继承和命名空间绕一圈就不得而知了

batsong@21IC(6335473) 22:31:20

那个生成的ui.h我看了好几天

batsong@21IC(6335473) 22:31:45

确实有点绕

lxyppc(19148022) 22:32:46

UI中生成了三样东西

1. 所有UI文件中的UI元素

2. 初始化UI元素的函数。setupUI

3. 自动翻译调用的函数.retranslateUI

lxyppc(19148022) 22:33:02

这三样东西都整合在一个类中

John Lee(1513562323) 22:33:33

实在不习惯qt的camel命名方式

lxyppc(19148022) 22:33:42

这个类被和你主窗体同名的类继承,放在了命名空间ui中

John Lee(1513562323) 22:34:10

unix/linux的小写加下划线,microsoft的匈牙利,都习惯。

lxyppc(19148022) 22:34:45

我觉得只要风格一致就好的,以前看linux下纯小写的命名也不习惯,后来看多了也就那样

batsong@21IC(6335473) 22:35:07

大小写间隔输入起来我不习惯

batsong@21IC(6335473) 22:35:16

很慢

John Lee(1513562323) 22:36:47

我写windows程序时,就自然会用匈牙利,而非windows程序,就自然而然的用linux风格了。

lxyppc(19148022) 22:37:33

我现在已经凌乱了

batsong@21IC(6335473) 22:37:50

我已经转向汉语拼音了、

John Lee(1513562323) 22:38:06

好像java也是camel风格的?

lxyppc(19148022) 22:39:11

汉语同音字太多了

lxyppc(19148022) 22:39:45

嗯,java和qt风格差不多

batsong@21IC(6335473) 22:40:19

.LIB 和 .dll里面存的是源码还是机器码?

John Lee(1513562323) 22:44:08

lib里是relocatable的机器码,dll里面是pic机器码。

batsong@21IC(6335473) 22:45:47

那覆盖靠什么识别,标识符都没有了

John Lee(1513562323) 22:47:17

覆盖?

batsong@21IC(6335473) 22:47:46

虚函数

batsong@21IC(6335473) 22:49:07

我把一个模块编译成.LIB

John Lee(1513562323) 22:49:45

relocatable

batsong@21IC(6335473) 22:49:48

然后从lib继承实现虚函数的功能,可行不?

日期:2011/12/23

John Lee(1513562323) 22:51:00

lib继承?

batsong@21IC(6335473) 22:52:14

我没搞过lib,我想把一个模块编译出来实现黑箱,模块里面定义了类型和方法

John Lee(1513562323) 22:52:46

实例在外面创建?

batsong@21IC(6335473) 22:52:50



John Lee(1513562323) 22:53:21

最好不要这样

batsong@21IC(6335473) 22:53:35

为啥?

John Lee(1513562323) 22:53:39

==,你用lib,不是dll

John Lee(1513562323) 22:53:41

?

batsong@21IC(6335473) 22:53:56

就是KEIL 或者IAR

John Lee(1513562323) 22:54:07

哦,那就没关系

lxyppc(19148022) 22:54:19

无所谓了 (来自iPad QQ: http://mobile.qq.com/v/ )

batsong@21IC(6335473) 22:54:40



lxyppc(19148022) 22:55:04

就是这样做的

John Lee(1513562323) 22:55:16

如果是动态链接库,最好使用类静态函数创建对象。

John Lee(1513562323) 22:55:47

而不在外部创建对象。

John Lee(1513562323) 22:56:18

如果是lib,无所谓,反正应用程序都要重新build的。

batsong@21IC(6335473) 22:59:03

把各个逻辑和算法模块做成lib,硬件相关部分用虚函数,在应用里面继承

John Lee(1513562323) 22:59:20

可以

batsong@21IC(6335473) 22:59:21

可以用在不同平台的产品上

batsong@21IC(6335473) 23:00:00

lib是不是只能包含方法和类型,不能分配空间?

John Lee(1513562323) 23:00:21

可以啊

batsong@21IC(6335473) 23:00:55

LIB是不是可以理解为加密了的源码

batsong@21IC(6335473) 23:01:37

每次build还要的

John Lee(1513562323) 23:01:49

虚表也可以包含在lib中,但虚表本身是weak的,目的是为了防止多个虚表冲突。

batsong@21IC(6335473) 23:03:54

今天学的很满足,老师早点休息

使用特权

评论回复
地板
xyz549040622|  楼主 | 2011-12-27 11:21 | 只看该作者
John Lee(1513562323) 22:20:38

不见得,new也是可以重载的。

batsong@21IC(6335473) 22:21:13

关键字也能重载

John Lee(1513562323) 22:21:49

如果Ui::MainWindow(这是一个类吧?)中重载了new,那么 new Ui::MainWindow就要按重载的new来操作。

lxyppc(19148022) 22:22:07

关键字和运算符重载也是C++难懂的原因之一

batsong@21IC(6335473) 22:22:45

我以前看的书上没看到关键字重载

batsong@21IC(6335473) 22:22:47

新特性?

lxyppc(19148022) 22:23:05

new是一种运算符

John Lee(1513562323) 22:23:59

class foo {

    operator new (size_t size) { ... };

    ...

}



foo* p = new foo;

日期:2011/12/23

John Lee(1513562323) 22:24:39

这个new foo,就要调用foo::new来分配。这就可以用户定制分配方法。

batsong@21IC(6335473) 22:25:22

没有一个对象来调用new啊

John Lee(1513562323) 22:26:43

这个特殊语法,编译器首先看要new的类(foo)中有没有重载new,如果有,就用之,否则,就用全局的new.

batsong@21IC(6335473) 22:26:55



lxyppc(19148022) 22:27:31

这个地方这样写

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

}

和这样写

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui = new Ui::MainWindow;

    ui->setupUi(this);

}

是等效的,Qt中这样使用new没有特别的含义

lxyppc(19148022) 22:30:48

但是为什么Qt要用继承和命名空间绕一圈就不得而知了

batsong@21IC(6335473) 22:31:20

那个生成的ui.h我看了好几天

batsong@21IC(6335473) 22:31:45

确实有点绕

lxyppc(19148022) 22:32:46

UI中生成了三样东西

1. 所有UI文件中的UI元素

2. 初始化UI元素的函数。setupUI

3. 自动翻译调用的函数.retranslateUI

lxyppc(19148022) 22:33:02

这三样东西都整合在一个类中

John Lee(1513562323) 22:33:33

实在不习惯qt的camel命名方式

lxyppc(19148022) 22:33:42

这个类被和你主窗体同名的类继承,放在了命名空间ui中

John Lee(1513562323) 22:34:10

unix/linux的小写加下划线,microsoft的匈牙利,都习惯。

lxyppc(19148022) 22:34:45

我觉得只要风格一致就好的,以前看linux下纯小写的命名也不习惯,后来看多了也就那样

batsong@21IC(6335473) 22:35:07

大小写间隔输入起来我不习惯

batsong@21IC(6335473) 22:35:16

很慢

John Lee(1513562323) 22:36:47

我写windows程序时,就自然会用匈牙利,而非windows程序,就自然而然的用linux风格了。

lxyppc(19148022) 22:37:33

我现在已经凌乱了

batsong@21IC(6335473) 22:37:50

我已经转向汉语拼音了、

John Lee(1513562323) 22:38:06

好像java也是camel风格的?

lxyppc(19148022) 22:39:11

汉语同音字太多了

lxyppc(19148022) 22:39:45

嗯,java和qt风格差不多

batsong@21IC(6335473) 22:40:19

.LIB 和 .dll里面存的是源码还是机器码?

John Lee(1513562323) 22:44:08

lib里是relocatable的机器码,dll里面是pic机器码。

batsong@21IC(6335473) 22:45:47

那覆盖靠什么识别,标识符都没有了

John Lee(1513562323) 22:47:17

覆盖?

batsong@21IC(6335473) 22:47:46

虚函数

batsong@21IC(6335473) 22:49:07

我把一个模块编译成.LIB

John Lee(1513562323) 22:49:45

relocatable

batsong@21IC(6335473) 22:49:48

然后从lib继承实现虚函数的功能,可行不?

日期:2011/12/23

John Lee(1513562323) 22:51:00

lib继承?

batsong@21IC(6335473) 22:52:14

我没搞过lib,我想把一个模块编译出来实现黑箱,模块里面定义了类型和方法

John Lee(1513562323) 22:52:46

实例在外面创建?

batsong@21IC(6335473) 22:52:50



John Lee(1513562323) 22:53:21

最好不要这样

batsong@21IC(6335473) 22:53:35

为啥?

John Lee(1513562323) 22:53:39

==,你用lib,不是dll

John Lee(1513562323) 22:53:41

?

batsong@21IC(6335473) 22:53:56

就是KEIL 或者IAR

John Lee(1513562323) 22:54:07

哦,那就没关系

lxyppc(19148022) 22:54:19

无所谓了 (来自iPad QQ: http://mobile.qq.com/v/ )

batsong@21IC(6335473) 22:54:40



lxyppc(19148022) 22:55:04

就是这样做的

John Lee(1513562323) 22:55:16

如果是动态链接库,最好使用类静态函数创建对象。

John Lee(1513562323) 22:55:47

而不在外部创建对象。

John Lee(1513562323) 22:56:18

如果是lib,无所谓,反正应用程序都要重新build的。

batsong@21IC(6335473) 22:59:03

把各个逻辑和算法模块做成lib,硬件相关部分用虚函数,在应用里面继承

John Lee(1513562323) 22:59:20

可以

batsong@21IC(6335473) 22:59:21

可以用在不同平台的产品上

batsong@21IC(6335473) 23:00:00

lib是不是只能包含方法和类型,不能分配空间?

John Lee(1513562323) 23:00:21

可以啊

batsong@21IC(6335473) 23:00:55

LIB是不是可以理解为加密了的源码

batsong@21IC(6335473) 23:01:37

每次build还要的

John Lee(1513562323) 23:01:49

虚表也可以包含在lib中,但虚表本身是weak的,目的是为了防止多个虚表冲突。

batsong@21IC(6335473) 23:03:54

今天学的很满足,老师早点休息

使用特权

评论回复
5
batsong| | 2011-12-27 18:27 | 只看该作者
后面还有我和老师的聊天记录。。。

使用特权

评论回复
6
xyz549040622|  楼主 | 2011-12-27 19:16 | 只看该作者
嘎嘎,与课程无关,删了:lol

使用特权

评论回复
7
plc_avr| | 2011-12-28 07:31 | 只看该作者
顶,谢谢上传

使用特权

评论回复
8
xyz549040622|  楼主 | 2011-12-28 08:59 | 只看该作者
7# plc_avr 烈火哥客气喽,这篇传的迟了,老早没人传,老师生气了,我才弄得,哎

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群: 嵌入式系统arm初学者 224636155←← +→→点击-->小 i 精品课全集,21ic公开课~~←←→→点击-->小 i 精品课全集,给你全方位的技能策划~~←←

2782

主题

19266

帖子

104

粉丝