标签 c/c++ 下的文章

模板是C++中一个重要的部分,也是泛型编程的基础,一个模板就是一个创建类或函数的蓝图,使用它在很多时候都能给我们带来巨大的便利。

一、函数模板

定义一个函数模板的语法为:

template <typename T>
int compare(const T &v1, const T &v2)
{
    if (v1 < v2) return -1;
    else if (v1 > v2) return 1;
    else return 0;
}

模板以关键字template 开始,后面跟一个模板参数列表,和函数的形参一样,参数列表可以是多个以逗号隔开的一个或多个参数,外部用<> 包起来。

T 代表一种数据类型,可以为任意的内置类型或自定义类,只要该类型实现了函数重载,就可以通过compare() 函数进行比较。

- 阅读剩余部分 -

0x01 介绍

C++类中有两种方式可以用来初始化成员变量,一种最常见的是在构造函数内部直接对成员函数赋值:

class CTest{
    int m_a, m_b;
    CTest(int a, int b){
        m_a = a;
        m_b = b;
    }
}

另外一种方式就是通过构造函数的初始值列表来完成初始化:

class CTest{
    int m_a, m_b;
    CTest(int a, int b) : m_a(a), m_b(b){}
}

这种在构造函数后加一个冒号然后初始化的方式叫做构造函数初始值列表,它更优于第一种初始化方式。

0x02 初始值列表的必要性

在以下情况下,必需使用初始值列表方式来初始化:

  • 类成员包含const对象时。
  • 在类A没有提供默认构造函数且被类B包含或者继承时,类B必需使用默认初始化方式初始化A。

对于第一个条件比较好理解,因为const本身在初始化后是无法再赋值的,所以必须使用初始化列表来对其初始化。

对于第二种情况,因为根据构造函数的执行顺序,在构造类B时必须先构造类A的构造函数,但类A并没有提供默认的构造函数,此时导致编译器找不到合适的构造函数,所以对象构造失败。因此这里必须在初始值列表中初始化。

#pragma once
#include <iostream>
class CAnimal
{
public:
    CAnimal(int weight) :m_weight(weight) {
    }
    int m_weight;
};

class CDog {
public:
    CAnimal m_a;
    const int m_b;
    CDog(int a, int b) : m_b(b), m_a(a){
    }
};

0x02 初始值列表的效率

使用普通方式初始化时编译器会先执行一次对象的默认构造函数,然后才会对其赋值,初始化时执行了两个步骤。

#include <iostream>
class CAnimal
{
public:
    CAnimal() { std::cout << "default" << std::endl; }  // 添加默认初始化函数
    CAnimal(int weight) :m_weight(weight) {
    }
    int m_weight;
};

class CDog : public CAnimal {
public:
    CDog(int weight) {
        m_weight = weight;
    }
    // 初始值列表,和上面的构造函数不可共存
    CDog(int weight): CAnimal(weight) {
    }
};

执行CDog构造函数时会先执行CAnimal的默认构造函数,输出defualt 然后后才会执行m_weight = weight。但是对于初始值列表方式来说并不会执行两步,直接通过相应的构造函数初始化就完成了,相对来说简化了一个过程,效率肯定也会高一些。

0x03 初始化顺序

使用初始值列表初始化时,初始化的顺序是根据成员变量定义的顺序来的,并不是初始值列表的顺序。

class CAnimal
{
public:
    CAnimal(int weight) :m_weight(weight) {
        std::cout << weight << std::endl;
    }
    int m_weight;
};

class CDog {
public:
    CAnimal m_a, m_b;
    CDog(int a, int b) : m_b(b), m_a(a){
    }
};

实例一个对象CDog d(1, 2) ,结果会输出:

1
2

并不是根据初始值列表先用2初始化m_b,可见初始顺序是根据定义顺序来的。

一、概述

X-Forwarded-For, X-Real-IP, remote_addr是http协议中用来表示客户端地址的请求头。

X-Forwarded-ForX-Real-IP只有请求存在代理时才有值,而remote_addr一直存在。

  • X-Forwarded-For:记录代理服务器的地址,每经过一个代理,该字段会加上一个记录。格式形如:1.1.1.1, 2.2.2.2
  • X-Real-IP:也是用来记录服务器的地址,但是和上面的不同,它不把记录添加到结尾,而是直接替换
  • remote_addr:上一个客户端连接的地址,不存在代理就表示客户端的地址,存在代理就表示最后一个代理服务器的地址

- 阅读剩余部分 -

一、概述

const 的引用通常被称为常量引用 ,它和非常量引用的区别为:

  • 非常量引用可以修改绑定对象的值,常量引用不能修改绑定对象的值。
  • 非常量引用时绑定对象的类型必须严格匹配,常量引用只要绑定的对象可以转换成引用的类型即可,即它的绑定值可以是表达式等等。
  • 非常量引用不能引用常量和常量引用对象,常量引用可以引用普通的常量和常量引用对象。
  • 非常量引用不能引用字面量,常量引用可以引用字面量。

- 阅读剩余部分 -

使用CDN的时候遇到了跨域的问题,在网上找解决方法都是说在nginx里面加上请求头,然而设置了请求头后发现还是没有解决问题。所以为了解决问题,并且彻底弄清楚这其中的原理,花了半天时间仔细分析了一下。

一、什么是跨域

1.1 跨域描述

跨域是一种安全机制,使浏览器只能在页面内执行同源站点的脚本文件,避免出现跨站脚本调用。

- 阅读剩余部分 -

HTTP协议(一):概述

一、概述

超文本传输协议(Hypertext Transfer Protocol, HTTP)是当今网络的重要角色之一,也是万维网(World Wide Web, WWW)的核心组成。它的特点为:

  • 无连接:HTTP是一个无连接的协议,虽然基于TCP,但是每次进行数据交互之前,无需先建立HTTP连接。
  • 无状态:HTTP协议不保存任何连接的状态和连接时的数据信息,每一个新的连接都是完全陌生的。

它是一个基于TCP的协议,因此,每次连接的建立和关闭都要进行三次握手四次挥手操作。

- 阅读剩余部分 -

一、概述

几乎所有的数据包都是通过以太网来传输,所以使用wireshark抓取以太网数据包非常容易,这里我们以DNS数据包为例。

二、抓包

1. 准备数据

打开wireshark,在筛选栏输入dns,点击开始抓包,然后打开命令提示符,输入ping www.baidu.com ,此时wireshark将会抓到以下数据:

- 阅读剩余部分 -