C++
常量
类型转换
静态变量
赋值运算符
本文总结了静态成员的使用、单例的实现、常量对象与常量方法,以及如何将常量方法重载为普通方法。
静态成员
对象成员的声明前加static
即可定义为静态成员,静态成员必须在声明类的文件中进行声明(通常会初始化),否则链接错。
访问静态成员可以通过类名,也可以通过对象名。
class CPerson{
static int count;
};
int CPerson::count = 0;
CPerson p1, &p2 = p1, *p3 = new CPerson();
cout<<CPerson::count<<endl;
cout<<p1.count<<endl;
cout<<p2.count<<endl;
cout<<p3->count<<endl;
- 只有静态常量整型才可以在类的声明中,直接初始化。
sizeof
运算符不会计算静态常量。
- 静态方法不可访问非静态成员、
this
指针。
单例的实现
在C++中,借由静态成员变量,可以实现单例模式。首先需要将构造函数私有化,并提供获取单例的方法。
此后还需禁止复制构造函数、禁止赋值运算符。
class CPerson{
private:
static CPerson* p;
CPerson(){};
CPerson(CPerson&);
const CPerson& operator= (const CPerson&);
public:
static Person* instance(){
return p ? p : (p = new P());
}
};
CPerson* CPerson::p = NULL;
C++
栈
内存
指针
构造函数
析构函数
类型转换
赋值运算符
拷贝构造函数
本文总结了类的创建、复制和销毁过程中涉及到的成员函数:构造函数、析构函数、拷贝构造函数、赋值运算符等。
探讨了全局对象、静态对象、栈中的对象、堆中的对象的整个生命周期中,这些成员函数的调用时机。
类的声明
C++引入类的概念来实现面向对象程序设计,先来看一个简单的类的声明:
class CPerson{
public:
// 构造函数
CPerson(){
cout<<"constructor"<<endl;
}
// 构造函数(重载)
CPerson(int age){
cout<<"constructor "<<age<<endl;
}
// 声明可以与实现分离
void Hello();
};
CPerson::Hello(){
cout<<"hello"<<endl;
};
- 构造函数定义为私有,可以防止该类被直接实例化。一般用于Singleton实现。
- 不允许签名为
CPerson(CPerson p){}
的构造函数(编译错)。不允许带参数的析构函数(编译错)。构造函数可以有参数,不允许有返回值。总之,析构函数和构造函数签名不正确都会编译错。
对象实例化
可以直接定义对象变量,在栈中分配并初始化对象;也可以定义对象指针,从堆中分配空间并初始化对象。
CPerson p1;
CPerson p2(2);
CPerson* p3 = new CPerson(3);
输出:
constructor
constructor 2
constructor 3
CSS
HTML
inline
inline-block
盒模型
元素对齐是CSS中最常见的问题之一,控制元素对齐的属性包括text-align
, verticle-align
, margin
, line-height
等。
本文便来探讨inline元素的对齐行为,以及text-align
和verticle-align
的使用方法,并给出实例。
text-align
text-align指定了行内内容(例如文字)如何相对它的块父元素对齐。作用于当前元素的子元素,且子元素需是inline
的。例如:
常用的取值有:left
, right
, center
。
<style>
.right{
text-align: right;
}
</style>
<div class="right">
<span>Gesetz zur Änderung des Fernstra</span>
</div>
vertical-align
vertical-align指定行内(inline)元素或表格单元格(table-cell)元素的垂直对齐方式。
与text-align
不同,vertical-align
作用于当前元素。
为什么要是行内元素呢?因为如果是块元素的话,它总是会占据整行,就无所谓谁和谁垂直对齐了。
常用的取值有:top
, bottom
, middle
,默认值为baseline
。
CSS
DOM
HTML
inline
inline-block
overflow
text-overflow
white-space
盒模型
CSS 将 DOM 树转换为由矩形 Box 构成的树,并通过设置这些 Box 的属性来改变其位置和大小,描述每个元素或文本的布局。这些 Box 分为三个级别:
block-level
Box:display
属性为block
的Box,比如段落标签<p>
;
inline-level
Box:display
属性为inline-block
的Box,它们就像一行中的单词一样布局。它里面可以包含其他inline-level
的Box,也可以包含block-level
的Box;
- Line Box:一行单词就构成一个LineBox,这种Box是自动生成的,可以看做是
inline-level
Box的容器。
溢出、折行、断词是Line Box中常见的问题,设置这些行为的CSS属性包括white-space
、line-spacing
、text-overflow
、word-wrap
、word-break
等。
下面几小节中详细介绍这些属性的取值与对应的行为、以及常见的使用方法。
更多信息请参考:W3C 标准:CSS3-Box
line Box
下面的小节中介绍的CSS属性只适用于LineBox,那么什么是LineBox呢?请看下面的HTML片段:
<ul>
<li>The first item in the list.
<li>The second item.
</ul>
ul
会生成一个block-level
的 Box,然后为每个li
元素生成一个block-level
的 Box。
而每个li
的 Box 中有一个Line Box,它包含了两个inline-level
的 Box:
一个用来显示“ · ”,一个用来显示文本。
如果li
产生了换行,将会变成多个inline-level
Box,如果在ul
中间产生了分页,那么ul
会显示为两个block-level
Box。
AngularJS
HTML
JavaScript
MVC
模板
路由
AngularJS的ng-route模块为控制器和视图提供了[Deep-Linking]URL。
通俗来讲,ng-route模块中的$route
Service监测$location.url()
的变化,并将它映射到预先定义的控制器。也就是在客户端进行URL的路由。
下面首先给出$route
的使用示例,然后引入一个更加强大的客户端路由框架ui-router。
Angular 路由
在APP中定义多个页面的控制器,并给出对应的模板。然后$routeProvider
进行配置,即可将URL映射到这些控制器和视图。
首先定义一个基本的Angular APP,并引入ngRoute
:
Angular$route
Service在ngRoute
模块里。需要引入它对应的javascript文件,并在我们的APP里ngRoute
添加为模块依赖(如何添加模块依赖?)。
var app = angular.module('ngRouteExample', ['ngRoute'])
.controller('MainController', function($scope) {
})
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/users', {
templateUrl: 'user-list.html',
controller: 'UserListCtrl'
})
.when('/users/:username', {
templateUrl: 'user.html',
controller: 'UserCtrl'
});
// configure html5
$locationProvider.html5Mode(true);
});
上述代码中,$routeProvider
定义了两个URL的映射:/users
使用user-list.html
作为模板,UserListCtrl
作为控制器;
/users/:username
则会匹配类似/users/alice
之类的URL,稍后你会看到如何获得:username
匹配到的值。先看首页的模板:
HTML5Mode: 服务器端路由和客户端路由的URL以#
分隔。例如/foo/bar#/users/alice
,Angular通过操作锚点来进行路由。
然而html5Mode(true)
将会去除#
,URL变成/foo/bar/users/alice
(这需要浏览器支持HTML5的,因为此时Angular通过pushState
来进行路由)。
此时服务器对所有的客户端路由的URL都需要返回首页(/foo/bar
)视图,再交给Angular路由到/foo/bar/users/alice
对应的视图。
<div ng-controller="MainController">
Choose:
<a href="users">user list</a> |
<a href="users/alice">user: alice</a>
<div ng-view></div>
</div>
注意到模板文件中有一个div[ng-view]
,子页面将会载入到这里。
AngularJS
HTML
JavaScript
MVC
模块化
依赖注入
工厂方法
构造函数
AngularJS使用模块化的组织方式,和依赖注入的设计。这使得模块之间耦合度较低,模块更容易复用。同时支持声明式的编程风格。
在你创建Angular Module 或者 Service 之前,首先需要了解一下 Angular Module 和 Service 的工作方式。
模块概念
在Angular中,一个Module通常对应一个js文件,其中可以包括Controller、Service、Filter、Directive等。
下面我们声明一个模块:helloApp
,并在其中声明一个Controller:worldCtrl
,一个Directive:customer
,和一个Filter:count
。
接着在模板中,使用上面声明的helloApp
模块作为Angular APP:
- Module依赖:在声明
helloApp
模块时,需要给出依赖模块的列表。同时这些模块对应的JS需要在HTML中加以引入。在helloApp
中可以直接使用依赖模块中声明的Service、Directive、Filter。
- Service依赖:在声明Controller、Service、Directive、Filter的工厂方法中,把依赖的Service直接放到参数列表,Angular Injector会为你生成这些Service的实例。
AngularJS
DOM
HTML
HTTP
JavaScript
MVC
WebSocket
事件
回调函数
数据绑定
数据绑定可以说是AngularJS最大的特色。在Angular中,视图和模型的数据不仅是双向绑定的,并而且是实时的。
使用Angular可以做到良好的甚至是神奇的用户体验,例如用户在输入表单的过程中实时地提示输入有误或者输入正确。
双向绑定
下图是模板引擎中常见的单向数据绑定:
通常在服务器端,将数据模型和模板结合,生成视图。当视图中的数据发生改变时,数据模型不会自动更新;模型发生改变时,视图也不会自动刷新。
因此开发者不得不写大量的代码来同步视图和模型。例如:
- 视图->模型:绑定DOM事件来监听视图的改变,进而通过javascript函数来同步数据模型,更改javascript对象,或者发送HTTP请求到后台。
- 模型->视图:模型改变时通过jQuery操作来更新DOM。如果数据模型在后台,可能还需要websocket之类的推送机制。
而Angular提供了双向的数据绑定,我们可以在Angular Controller的$scope
中声明数据模型,在模板中进行绑定。
Angular会自动添加DOM事件,并在$scope
发生改变时自动进行DOM操作。下面是Angular双向绑定的MVT关系示意图:
图片来源: https://docs.angularjs.org/guide/databinding