其实到了这个层次的lua语法(用一个类去实现另一个类),我已经不是太了解了,Programming in lua中也没有出现类似的语法,只简单的提到了怎么去New,书中是用这种方式去实现继承的。第19行的语法纯粹是自己摸索出来的,一开始用self:Size(),结果并没有从CList中去找,而是陷入了纯粹的递推自身调用。
1 g='hi~' 2 local g='hello!' 3 for i=1,2do 4 g = g .. '1' 5 print(g) 6 end 7 print(g)
输出:
hello!1
hello!11
hello!11
证明内部变量g的使用,实际是用了外部的变量g
最后来个复杂点的例子:
test5:
1 g='hi~' 2 local g='hello!' 3 for i=1,2do 4 print(x) 5 x = x and x .. '1'or g .. '1' 6 print(x) 7 local x = x .. '1' 8 print(x) 9 local x = x .. '1' 10 print(x) 11 end 12 print(x)
1 g
= {} 2 for i=1,2do 3 io.write("global
g:") 4 print(g) 5 local g = {} 6 io.write("first
local g:") 7 print(g) 8 local g = {} 9 io.write("second
local g:") 10 print(g) 11 end 12 print(g)
1 #!/usr/bin/env lua 2 3 g = '1' 4 for i=1,2do 5 g = g .. '2' 6 local g = '3' 7 local g = g .. '4' 8 g = g .. '5' 9 local i = 1 10 whiletruedo 11 local name,value = debug.getlocal(1,i) 12 ifnot name then 13 break 14 end 15 16 print(name, value) 17 i
= i + 1 18 end 19 end
这里想提出的一点就是lua中实在是没有一个可用的debug工具,注意我的措辞,是连一个可用的都没有,更别提好用的了。相对而言C++有VS+gdb,python用pydb,bash有bashdb,而lua什么都没有!lua for windows的那个scite别提多不好用了,clidebug,xdblua, RemDebug等等我都用过,甚至官网提到的几个IDE我都试用了一下,通通的不能用,可能是因为lua升级了的原因(记得scite在原来是可用的),郁闷死我了。作为一个两百多行的list代码,没有一个可用的调试工具,简直就是噩梦(也许没有那么夸张,但是的确浪费了我很多本来简单调试就可以发下你的问题),唉。。。。。在没有好用的lua调试工具之前,我甚至都有点不想给自己找罪受了。再也不写太多的lua代码了。最多在小程序中用print和assert勉强写写吧。其实感觉lua本身对于调试的支持是很到位的了,为什么却没有好用的工具呢?唉。。。。。。。。。。这就是普及的好处了。。。。。真有时间,哥们自己DIY一个用用算了。
1 #!/usr/bin/env lua 2 3 --
require "std" 4 5 --
Node prototype 6 CNode = {} 7 function CNode:New(data,
prev, next) 8 local o = {} 9 o.data
= data 10 o.prev =
prev 11 o.next = next 12 o.type = "CNode" 13 setmetatable(o, self) 14 self.__index
= self 15 return o 16 end 17 18 --
iterator of list prototype like in C++ 19 CListIterator = {} 20 function CListIterator:New(a) 21 assert(a ~= niland 22 type(a) == "table"and 23 a.type ~= niland 24 ((a.type == "CList") or (a.type == "CNode")), 25 "Argument to new a CListIterator must be a CList
object or a CNode object") 26 27 local o = {} 28 -- give it a type name 29 o.type = "CListIterator" 30 31 -- if a is a CList object then create a begin iterator for
the object 32 -- if a is a CNode object then return a iterator point to
the node 33 if a.type == "CList"then 34 o.pos
= a.head.next 35 elseif a.type == "CNode"then 36 o.pos
= a 37 end 38 39 setmetatable(o, self) 40 self.__index
= self 41 return o 42 end 43 44 function CListIterator:IsEnd() 45 returnnot self.pos.data 46 end 47 48 function CListIterator:Cur() 49 return self.pos 50 end 51 52 function CListIterator:MoveNext() 53 self.pos =
self.pos.next 54 return self 55 end 56 57 function CListIterator:MovePrev() 58 self.pos =
self.pos.prev 59 return self 60 end 61 62 -- List
prototype 63 CList = {} 64 function CList:CreateIterator() 65 return CListIterator:New(self) 66 end 67 68 function CList:New() 69 local o = {} 70 o.head =
CNode:New() 71 o.head.prev
= o.head 72 o.head.next = o.head 73 74 -- give it a type def 75 o.type = "CList" 76 setmetatable(o, self) 77 self.__index
= self 78 return o 79 end 80 81 function CList:Insert(it,
data) 82 assert(it ~= nil, "Must pointer where to Insert") 83 assert(type(it) == "table", "Fisrt
Argument must be a CListIterator(now it even not a table)") 84 assert(type ~= nil, "Fisrt
Argument must be a CListIterator(now it.type == nil)") 85 assert(it.type == "CListIterator", "Fisrt Argument must be a CListIterator") 86 87 local iter = CListIterator:New(self) 88 local node = CNode:New(data, it.pos.prev,
it.pos) 89 it.pos.prev.next = node 90 it.pos.prev
= node 91 return CListIterator:New(node) 92 end 93 94 function CList:Begin() 95 return self:CreateIterator() 96 end 97 98 function CList:End() 99 return CListIterator:New(self.head) 100 end 101 102 103 function CList:PushFront(data) 104 self:Insert(self:Begin(),
data) 105 end 106 107 function CList:PushBack(data) 108 self:Insert(self:End(),
data) 109 end 110 111 function CList:IsEmpty() 112 return self:Begin().pos == self:End().pos 113 end 114 115 function CList:Erase(it) 116 assert(not it.data, "you can't erase the head") 117 it.pos.prev.next = it.pos.next 118 it.pos.next.prev = it.pos.prev 119 it = nil 120 end 121 122 function CList:PopFront() 123 assert(not self:IsEmpty(), "Can't PopFront to a Empty list") 124 self:Erase(self:Begin()) 125 end 126 127 function CList:PopBack() 128 assert(not self:IsEmpty(), "Can't PopBack to a Empty list") 129 self:Erase(self:End():MovePrev()) 130 end 131 132 function CList:Clear() 133 whilenot self:IsEmpty() do 134 self:Erase(self:Begin()) 135 end 136 end 137 138 -- redefine
global print to support the CList 139 p = _G.print 140 functionprint(o) 141 if o ~= nilandtype(o)
== "table"and 142 o.type ~= niland o.type == "CList"then 143 -- iterate like in C++ using CList and CListIterator feature 144 local it = o:CreateIterator() 145 whilenot it:IsEnd() do 146 io.write(it:Cur().data) 147 io.write(" ") 148 it:MoveNext() 149 end 150 io.write("/n") 151 else 152 p(o) 153 end 154 end 155 156 -- test
PushFront 157 print("/ntest: test PushFront and PopFront") 158 newlist = CList:New() 159 newlist:PushFront(10) 160 print(newlist) 161 newlist:PushFront(20) 162 print(newlist) 163 newlist:PushFront(30) 164 print(newlist) 165 newlist:PopFront() 166 print(newlist) 167 it = newlist:CreateIterator() 168 newlist:Erase(it) 169 print(newlist) 170 newlist:Clear() 171 print(newlist) 172 173 174 -- test
PushBack 175 print("/ntest: test PushBack and popBack") 176 newlist = CList:New() 177 newlist:PushBack(10) 178 print(newlist) 179 newlist:PushBack(20) 180 print(newlist) 181 newlist:PushBack(30) 182 print(newlist) 183 newlist:PopBack() 184 print(newlist) 185 newlist:PopFront() 186 print(newlist) 187 188 189 -- test: insert
at begin 190 print("/ntest: insert at begin ") 191 newlist = CList:New() 192 it = newlist:CreateIterator() 193 iter = newlist:Insert(it, 10); 194 io.write("cur iterator:" .. tostring(it.pos.data) .. "
return iterator:" .. tostring(iter.pos.data)
.. "/n") 195 print(newlist) 196 iter = newlist:Insert(it, 20); 197 io.write("cur iterator:" .. tostring(it.pos.data) .. "
return iterator:" .. tostring(iter.pos.data)
.. "/n") 198 print(newlist) 199 iter = newlist:Insert(it, 30); 200 io.write("cur iterator:" .. tostring(it.pos.data) .. "
return iterator:" .. tostring(iter.pos.data)
.. "/n") 201 print(newlist) 202 203 -- test: insert
at back 204 print("/ntest: insert at back") 205 newlist = CList:New() 206 it = newlist:CreateIterator() 207 it = newlist:Insert(it, 10); 208 io.write("cur iterator:" .. tostring(it.pos.data).."/n") 209 it = newlist:Insert(it, 20); 210 io.write("cur iterator:" .. tostring(it.pos.data).."/n") 211 it = newlist:Insert(it, 30); 212 io.write("cur iterator:" .. tostring(it.pos.data).."/n") 213 print(newlist) 214 215 -- iterate like
in C++ 216 print("/niterate like in C++") 217 it = newlist:CreateIterator() 218 whilenot it:IsEnd() do 219 io.write(it:Cur().data .. "
") 220 it:MoveNext() 221 end 222 print("/n") 223 224 -- closure list
iterator to iterate 225 print("/nclosure list iterator to iterate") 226 function list_iter(list) 227 local cur = list.head 228 returnfunction() 229 if cur.next.data
~= nilthen 230 cur
= cur.next 231 return cur.data 232 end 233 end 234 end 235 236 for v in list_iter(newlist) do 237 io.write(v .. "
") 238 end 239 240
--《数据结构b与算法分析c++描述》 Mark Allen Weiss著人民邮电大学出版中文版第78-81面,堆栈的应用(1) 队列(queue)的链表(list)实现及循环数组(circular array) C++实现,需要注意的是,仅仅为了说明问题,没有详细探究代码的健壮,比如,我没有加入错误检测,这点在循环数组的实现是非常容易出现的。并且为了说明问题,我用了一个很小的数组来实现,以完成真正的从尾部到头部的跳转。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stack> 4 #include <string> 5 #include <iostream> 6 #include <sstream> 7 #include "ExprComputer.h" 8 usingnamespace std; 9 10 int main(int argc, char*
argv[]) 11 { 12 CExprComputer
loExprComputer; 13 // all these below can work right,comment is same as the
content 'couted'. 14 stringstream lss; 15 lss << "1 + 2 * 3 ="; 16 17 cout <<"test trans stringstream in and cout." <<endl; 18 loExprComputer.TransInfix2Postfix(lss,
cout); 19 20 cout <<"test trans cin and cout." <<endl; 21 loExprComputer.TransInfix2Postfix(cin,
cout); 22 23 stringstream
lss2; 24 cout <<"test trans cin and stringstream out." <<endl; 25 loExprComputer.TransInfix2Postfix(cin,
lss2); 26 cout
<<lss2.str() <<endl; 27 28 lss.seekg(0); 29 cout <<"test stringstream in computeInfix." <<endl; 30 cout
<<lss.str(); 31 cout
<<loExprComputer.ComputeInfix(lss) <<endl; 32 33 cout <<"test cin in computeInfix." <<endl; 34 cout
<<loExprComputer.ComputeInfix(cin) <<endl; 35 36 stringstream
lssPostfix; 37 lssPostfix
<< "1 2 3 * + ="; 38 cout <<"test stringstream in ComputePostfix." <<endl; 39 cout
<<lssPostfix.str(); 40 cout
<<loExprComputer.ComputePostfix(lssPostfix) <<endl; 41 42 cout <<"test cin in ComputePostfix." <<endl; 43 cout
<<loExprComputer.ComputePostfix(cin) <<endl; 44 45 cout <<"Test completed." <<endl; 46 exit(0); 47 } 48
ExprComputer头文件:
1 #ifndef __EXPR_COMPUTE_H__ 2 #define
__EXPR_COMPUTE_H__ 3 #include <iostream> 4 #include <sstream> 5 #include <stack> 6 usingnamespace std; 7 8 // argument
to input 9 #define
_IN_ 10 11 // argument to
output 12 #define _OUT_ 13 14 class CExprComputer 15 { 16 public: 17 int ComputeInfix(_IN_ istream&
aisExpr); 18 int ComputePostfix(_IN_ istream&
aisExpr); 19 20 // Transform a infix expression to Postfix expression 21 int TransInfix2Postfix(_IN_ istream&
aisInfix, 22 _OUT_
ostream& aosPostfix); 23 24 private: 25 // Stack should be empty,Dump the information still in Stack
and exit 26 void DumpStack(); 27 28 // Output all information still in Stack 29 void OutputStack(); 30 31 // Make sure Stack is not empty when it should not. 32 void CheckStack(); 33 34 // I don't know why Stack operator is so few.And why I need
to 35 // clear the Stack in this example? GOD knows. 36 void ClearStack(); 37 38 // Read a int or a operator from a stream 39 bool ReadStream(_IN_ istream&
aisExpr, _OUT_ int&
aiReaded, _OUT_ bool&
abIsChar); 40 41 // Process a Operator 42 void ProcessOperator(char ac, _OUT_ ostream& aosPostfix); 43 44 void ComputeOperator(char ac); 45 46 stack<int> miSta; 47 }; 48 49 50 51 52 53 #endif 54
C++ is a complex language and an evolving
one, and its standard definition (the ISO C++ standard) was only recently
completed. As a result, your C++ compiler may
occasionally surprise you, even when its behavior is correct.
11.9.2. Name lookup, templates, and accessing members of
base classes
The C++ standard prescribes that all names that are not
dependent on template parameters are bound to their present definitions when
parsing a template function or class.[1] Only names that are dependent are looked
up at the point of instantiation. For example, consider
void foo(double);
struct A {
template <typename T>
void f () {
foo (1);// 1
int i = N;// 2
T t;
t.bar();// 3
foo (t);// 4
}
static const int N;
};
Here, the names foo and N appear in a
context that does not depend on the type of T. The compiler will thus
require that they are defined in the context of use in the template, not only
before the point of instantiation, and will here use ::foo(double) and A::N, respectively. In particular, it will convert the integer value
to a double when passing it to ::foo(double).
Conversely, bar and the call to foo in
the fourth marked line are used in contexts that do depend on the type of T,
so they are only looked up at the point of instantiation, and you can provide
declarations for them after declaring the template, but before instantiating
it. In particular, if you instantiate A::f<int>, the last line
will call an overloaded ::foo(int) if one was provided, even if after
the declaration of struct A.
This distinction between lookup of dependent and
non-dependent names is called two-stage (or dependent) name lookup. G++
implements it since version 3.4.
Two-stage name lookup sometimes leads to situations with
behavior different from non-template codes. The most common is probably this:
template <typename T> struct Base {
int i;
};
template <typename T> struct Derived : public Base<T> {
int get_i() { return i; }
};
In get_i(), i is not used in a dependent
context, so the compiler will look for a name declared at the enclosing
namespace scope (which is the global scope here). It will not look into the
base class, since that is dependent and you may declare specializations of Base
even after declaring Derived, so the compiler can't really know what i
would refer to. If there is no global variable i, then you will get an
error message.
In order to make it clear that you want the member of the
base class, you need to defer lookup until instantiation time, at which the
base class is known. For this, you need to access i in a dependent
context, by either using this->i (remember that this is of
type Derived<T>*, so is obviously dependent), or using Base<T>::i.
Alternatively, Base<T>::i might be brought into scope by a using-declaration.
Another, similar example involves calling member functions
of a base class:
template <typename T> struct Base {
int f();
};
template <typename T> struct Derived : Base<T> {
int g() { return f(); };
};
Again, the call to f() is not dependent on
template arguments (there are no arguments that depend on the type T,
and it is also not otherwise specified that the call should be in a dependent
context). Thus a global declaration of such a function must be available, since
the one in the base class is not visible until instantiation time. The compiler
will consequently produce the following error message:
x.cc: In member function `int Derived<T>::g()':
x.cc:6: error: there are no arguments to `f' that depend on a template
parameter, so a declaration of `f' must be available
x.cc:6: error: (if you use `-fpermissive', G++ will accept your code, but
allowing the use of an undeclared name is deprecated)
To make the code valid either use this->f(), or Base<T>::f(). Using the -fpermissive flag will also let
the compiler accept the code, by marking all function calls for which no
declaration is visible at the time of definition of the template for later
lookup at instantiation time, as if it were a dependent call. We do not
recommend using -fpermissive to work around invalid code, and it will
also only catch cases where functions in base classes are called, not where
variables in base classes are used (as in the example above).
Note that some compilers (including G++ versions prior to
3.4) get these examples wrong and accept above code without an error. Those
compilers do not implement two-stage name lookup correctly.
《Inside C++ Object 》阅读笔记(2),看《Inside C++ Object 》的作用
write by 九天雁翎(JTianLing) --
blog.csdn.net/vagrxie
因为你永远也不可能完全弄清楚C++在你背后做了多少工作,所以你永远都会需要sizeof来帮助你确认你的判断。我从刚开始学C++到现在sizeof是用的不断,直到现在读《Inside C++ Object》还是会碰到。简直是无语。呵呵,用了这么多次的sizeof,少说也是有点经验的:)其实还是用宏的奇技淫巧而已,不推荐广泛使用。