C++手稿:类的静态和常量成员

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++ 内存 指针 构造函数 析构函数 类型转换 赋值运算符 拷贝构造函数

本文总结了类的创建、复制和销毁过程中涉及到的成员函数:构造函数、析构函数、拷贝构造函数、赋值运算符等。 探讨了全局对象、静态对象、栈中的对象、堆中的对象的整个生命周期中,这些成员函数的调用时机。

类的声明

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

inline元素的对齐问题

CSS HTML inline inline-block 盒模型

元素对齐是CSS中最常见的问题之一,控制元素对齐的属性包括text-align, verticle-align, margin, line-height等。 本文便来探讨inline元素的对齐行为,以及text-alignverticle-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>

css: pull right

vertical-align

vertical-align指定行内(inline)元素或表格单元格(table-cell)元素的垂直对齐方式。 与text-align不同,vertical-align作用于当前元素

为什么要是行内元素呢?因为如果是块元素的话,它总是会占据整行,就无所谓谁和谁垂直对齐了。

常用的取值有:top, bottom, middle,默认值为baseline

CSS Line Box:溢出与折行

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-levelBox的容器。

溢出、折行、断词是Line Box中常见的问题,设置这些行为的CSS属性包括white-spaceline-spacingtext-overflowword-wrapword-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-levelBox,如果在ul中间产生了分页,那么ul会显示为两个block-levelBox。

AngularJS 路由:ng-route 与 ui-router

AngularJS HTML JavaScript MVC 模板 路由

AngularJSng-route模块为控制器和视图提供了[Deep-Linking]URL。 通俗来讲,ng-route模块中的$routeService监测$location.url()的变化,并将它映射到预先定义的控制器。也就是在客户端进行URL的路由。 下面首先给出$route的使用示例,然后引入一个更加强大的客户端路由框架ui-router

Angular 路由

在APP中定义多个页面的控制器,并给出对应的模板。然后$routeProvider进行配置,即可将URL映射到这些控制器和视图。 首先定义一个基本的Angular APP,并引入ngRoute

Angular$routeService在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 模块化与依赖注入

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 数据绑定与 $digest 循环

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

上一页 下一页