各种CSS选择器的优先级

CSS HTML 伪类 选择符

由于规则之间可以互相覆盖、子元素会继承父元素的部分规则,导致了CSS冲突的问题。 碰到CSS冲突时,通常我们会加入一些更加详细的规则或调整规则顺序来解决冲突。 那么优先级究竟是如何定义的呢?

先给出结论:ID>类或伪类或属性>类型或伪元素>通配选择器, 外部样式表和内部样式表拥有相同的优先级, HTML style属性拥有最高优先级,浏览器默认样式(UA Default)优先级最低。 对于相同优先级的规则,写在后面的会覆盖前面的。

C++手稿:STL中的函数对象与函数指针

C++ STL 指针 模板 运算符 函数对象 函数指针

STL是C++的标准模板库(standard template library),自然其中定义的都是模板。 相比于类和函数声明的显式接口(explicit interface),类模板和函数模板声明的接口属于隐式接口(implicit interface)。 因为模板参数应当满足的接口是由模板中表达式的合法性决定的,这一点给了模板很大的自由。 而函数对象函数指针具有同样的调用语法,因此STL中这两者常常可以互换。

更多关于隐式接口和显式接口的概念和区别,参见Effective C++: Item 41

先来感受一下C++中的函数对象和函数指针:

template<typename T>
void printer(int a, int b, T func){
    cout<<func(a, b)<<endl;
}

在STL中定义了很多像上面这样的模板,这里的T是一个可调用(实现了括号运算符)的东西。 这使得我们在使用模板时可以指定一个计算策略,它可以是函数对象,也可以是函数指针。

Less<int>便是一个常见的函数对象,常用来配置容器或算法。<functional>中定义了很多这样的函数对象。

函数指针

函数指针通常用来将函数传参或存储。例如:

int sum(int a, int b){
    return a+b;
}
int main(){
    printer(2, 3, sum);
    return 0;
}

上述的printer调用方式,编译器会生成对应的函数实例:

void printer(int a, int b, int (*func)(int, int)){
    cout<<func(a, b)<<endl;
}

这里T的类型是int (*)(int, int)

如果你是python或者javascript程序员的话,上述过程没有什么特别的。 唯一要注意的是func的声明方式,星号要和标识符括起来:(*func)

函数对象

函数对象是重载了括号运算符的类的实例,它也可以这样调用:func(a, b)。例如:

class Sum{
public:
    int operator()(int a, int b){
        return a+b;
    }
};

int main(){
    printer(2, 3, Sum());
    return 0;
}

编译器会生成这样的函数实例:

void printer(int a, int b, Sum s){
    cout<<s(a, b)<<endl;
}

函数对象可以实现更加复杂的有状态的运算,因为对象可以有更多的属性和方法。

C++手稿:std::string

C++ 字符串

字符串在很多编程语言中已经成为基本数据类型,C语言中我们使用char*来手动维护字符串的内存, 在C++中,可以使用std::string来方便地创建和操作字符串。

string是一个模板类,它有basic_string<T>定义:

typedef basic_string<char> string;

C++的string可以通过成员方法c_str()转换为C语言的char*

参考文档:cplusplus.com/string

初始化与赋值

string有两个常用的构造函数:

// 用一个C字符串构造
string str("hello");
// 等价于
string str = "hello";

也可以用N个同样的字符来构造字符串:string str2(8, 'x')

在C0x标准中,std::to_string可以将很多类型转换为一个string,可以代替itoa,例如:

string str = to_string(123);

string构造函数不接受charint类型。

字符串可以直接互相赋值,内存会自动拷贝和销毁,我们大可不必管它。对于单个字符赋值可以使用下标运算符:

for(int i=0;i<str.length(); i++){
    str[i] = 'a';
}

与多数class类似,string也提供了swapstr1.swap(s2)将会交换二者的值。

运算符支持

有通用运算符支持的数据类型往往更容易理解和操作,其中最讨人喜欢的莫过于+运算符:

str += str2;
str = str + "hello";

当然,你也可以直接调用append方法:str.append(str2)

除了+string还支持一系列的比较运算符:<, ==, >, <=, >=, !=

当然,你仍然可以直接调用compare方法:str1.compare(str2)str1小则会返回-1

C++手稿:封装与继承

C++ 封装 继承 作用域 多继承 名称隐藏 对象组合 构造函数 析构函数

本文总结了C++中类的继承相关的概念,包括可见性级别、继承的不同方式、构造与析构过程、封闭类、友元等。

可见性级别

C++类提供了数据结构和算法的封装,以及相应的3种可见级别。它们定义了不同的可见性:

  • Public:当前类以及子类的方法中可见,外部可见。
  • Protected:当前类以及子类的方法中可见,外部不可见。
  • Private:当前类的方法中可见,外部不可见。

在一个对象的成员函数中,可以调用其他同类对象的私有方法。

多数现代的面向对象语言中,仅提供Private和Public两种可见性,C++的可见级别略显复杂。 然而三种继承方式以及多继承机制,让问题更加复杂。简单起见,此处只讨论Private和Public方式的单继承。

  • Public继承:子类中可访问基类publicprotected成员,子类外部可见父类public成员。
  • Private继承:子类中可访问基类publicprotected成员,子类外部不可见父类成员。

类的继承

  • Public继承表示”is a”的关系(见Effective C++: Item 32),子类的对象同时也是一个基类的对象。 子类的行为应符合基类的行为,因此Public继承中通常不会覆盖基类成员。

  • Private继承表示“以…实现“的关系,子类是以基类来实现的 对于一个子类的对象,其外部不可见基类的行为。Private继承更像是对象组合。

对于Public继承,子类的指针、引用、变量可以直接赋值给基类的指针、引用、变量。

class CBase{};
class CDerived: public CBase{
public:
    CDerived(): CBase(){}
};

导航: 上一页 下一页

🔝