Castie!

正态分布, 优劣伴生

北冥有鱼,其名为鲲(kūn)。鲲之大,不知其几千里也;化而为鸟,其名为鹏。鹏之背,不知其几千里也;怒而飞,其翼若垂天之云。是鸟也,海运则将徙于南冥。南冥者,天池也。


北海若曰:“井鼃不可以语于海者,拘于虚也;夏虫不可以语于冰者,笃于时也;曲士不可以语于道者,束于教也。今尔出于崖涘,观于大海,乃知尔丑,尔将可与语大理矣。

C++ 一把剖析OC底层的军刀

GitHub Repo:coderZsq.github.io
Follow: coderZsq · GitHub
Resume: https://coderzsq.github.io/coderZsq.webpack.js/#/

日常扯淡

明天就要出国了, 所以本来想将.md的旅行攻略放到网上共享的, 就使用了简书的.md编译器, 没想到的是, 用完之后我的账号就被冻结了….

尊敬的简书用户您好,由于您有可能违反了简书社区管理规定(包括但不仅限于违反法律法规,不友善行为,发布垃圾信息,恶意行为如简信滋扰),具体可查看《「简书」指导原则和管理细则》http://dwz.cn/3BcYrg 和《简书社区指导规则》http://dwz.cn/3BcZi1 ,现根据情节严重程度,给予您冻结账户的惩罚,冻结期间帐号无法发表和编辑任何内容,您的数据将会为您保留60天,在此期间您可以备份您的文章,钱包里如有余额可及时提现,如您对结果处理有异议,也可联系邮箱 help@jianshu.com ,60天后将会直接注销您的账号并删除所有数据

真是的… 现在简书给我的印象是越来越差了, 随随便便写一点水文都有上千的阅读量, 而现在那个事件之后, 许多大佬的出走, 简书也可能对程序员这个群体不再重视了吧, 所以以后的文章会陆续发在掘金上. 简书的账号可能会在60天之后被删除吧… 也无所谓了…反正我已经全部迁移到githubpages上去了. 有兴趣的同学可以star关注.

上周我们就简单了解了, CC++之间的差异为切入点, 而有了上周的基础, 这次, 我们就能够更加深入的理解OC的底层实现原理了.

C++ 作者的建议

  1. 在C++中几乎不需要用宏, 用const和enum定义显式的常量, 用inline避免函数调用的额外开销, 用模板去刻画一组函数或类型, 用namespace去避免命名冲突.
  2. 不要在你需要变量之前去声明, 以保证你能立即对它进行初始化.
  3. 不要用malloc, new运算会做的更好.
  4. 避免使用void*, 指针算数, 联合和强制, 大多数情况下, 强制类型转换是设计错误的指示器.
  5. 尽量少用数组和C风格的字符串, 标准库中的string和vector可以简化程序.
  6. 更加重要的是, 试着将程序考虑为一组由类和对象表示的互相作用的概念年, 而不是一堆数据结构和一些可以拨弄的二进制.

自实现 string

string本质其实就是对char * 的包装, 而NSString也是如此.

int sq_strlen(const char * str) {
    int len = 0;
    while (*str++)
        len++;
    return len;
}

char * sq_strcpy(char * dst, const char * src) {
    char * d = dst;
    while ((*dst++ = *src++));
    return d;
}

int sq_strcmp(const char * str1, const char * str2) {
    for (; *str1 && *str2; str1++, str2++) {
        if (*str1 == *str2) {
            continue;
        } else {
            return *str1 - *str2;
        }
    }
    return *str1 - *str2;
}

char * sq_strcat(char * dst, const char * src) {
    char * d = dst;
    while (*dst)
        dst++;
    while ((*dst++ = *src++));
    return d;
}

我们先来自实现一下<string.h>中的常用方法, 代码公开了, 我就不细讲原理了, 自己多试试应该就能够有所领悟.

class SQString {
    
public:
    SQString(const char * str = nullptr);
    SQString(const SQString & another);
    SQString& operator=(const SQString & another);
    bool operator==(const SQString & another);
    bool operator>(const SQString & another);
    bool operator<(const SQString & another);
    bool operator>=(const SQString & another);
    bool operator<=(const SQString & another);
    SQString operator+(const SQString & another);
    SQString& operator+=(const SQString & another);
    ~SQString();
    char at(int n);
    char operator[](int n);
    char * c_str();
    void description();
private:
    char * _str;
};

猜测string内部实现原理, 其实就是构造器, 拷贝构造器, 运算符重载, 和一些常用函数的封装罢了, 并没有什么很神奇的东西.

SQString::SQString(const char * str) {
    if (str == nullptr) {
        _str = new char[1];
        *_str = '\0';
    } else {
        _str = new char[sq_strlen(str) + 1];
        sq_strcpy(_str, str);
    }
}

SQString::SQString(const SQString & another) {
    _str = new char[sq_strlen(another._str) + 1];
    sq_strcpy(_str, another._str);
}

SQString& SQString::operator=(const SQString & another) {
    if (this == &another) {
        return *this;
    }
    delete []this->_str;
    _str = new char[sq_strlen(another._str) + 1];
    sq_strcpy(_str, another._str);
    return *this;
}

bool SQString::operator==(const SQString & another) {
    return sq_strcmp(this->_str, another._str) == 0;
}
bool SQString::operator>(const SQString & another) {
    return sq_strcmp(this->_str, another._str) > 0;
}
bool SQString::operator<(const SQString & another) {
    return sq_strcmp(this->_str, another._str) < 0;
}
bool SQString::operator>=(const SQString & another) {
    return sq_strcmp(this->_str, another._str) >= 0;
}
bool SQString::operator<=(const SQString & another) {
    return sq_strcmp(this->_str, another._str) <= 0;
}

SQString SQString::operator+(const SQString & another) {
    int len = sq_strlen(this->_str) + sq_strlen(another._str);
    SQString str;
    delete []str._str;
    str._str = new char[len + 1]{0};
    sq_strcat(sq_strcat(str._str, this->_str), another._str);
    return str;
}
SQString& SQString::operator+=(const SQString & another) {
    int catLen = sq_strlen(this->_str);
    int srcLen = sq_strlen(another._str);
    int len = catLen + srcLen;
    this->_str = (char *)realloc(this->_str, len + 1);
    memset(this->_str + catLen, 0, srcLen + 1);
    sq_strcat(this->_str, another._str);
    return *this;
}

SQString::~SQString() {
    cout<<"delete: "<<this<<endl;
    delete []_str;
}

char SQString::at(int n) {
    return _str[n];
}

char SQString::operator[](int n) {
    return _str[n];
}

void SQString::description() {
    cout<<_str<<endl;
}

char * SQString::c_str() {
    return _str;
}

上面就是一些string的基础实现方式, 并没有超出上篇文章所涉及的范畴, 简单易理解, 对我们以后看runtime源码会有帮助.

int main(int argc, const char * argv[]) {
    
    SQString * s  = new SQString;
    SQString * s1 = new SQString("Castiel");
    SQString * s2 = new SQString(*s1);
    SQString   s3 = *s = *s1;
    SQString   s4 = *s1 + SQString(" is perpect!");
    SQString   s5 = SQString("Tell a joke: ") += s4;
    
    cout<<"s:  "; s->description();
    cout<<"s1: "; s1->description();
    cout<<"s2: "; s2->description();
    cout<<"s3: "; s3.description();
    cout<<"s4: "; s4.description();
    cout<<"s5: "; s5.description();

    if (*s == s3) {
        cout<<"*s == s3"<<endl;
    }
    if (*s2 >= s3) {
        cout<<"*s2 >= s3"<<endl;
    }
    if (*s < SQString("abc")) {
        cout<<"*s < SQString(\"abc\")"<<endl;
    }
    
    cout<<"s5.at(2): "<<s5.at(2)<<endl;
    cout<<"s5[5]: "<<s5[5]<<endl;
    cout<<"s5.c_str(): "<<s5.c_str()<<endl;

    cout<<"sizeof(SQString) : "<<sizeof(SQString)<<endl;
    
    delete s;
    delete s1;
    delete s2;
    
    return 0;
}

我们来用自实现的想系统的string一样使用, 会感觉并无差别.

delete: 0x7ffeefbff560
delete: 0x7ffeefbff550
s:  Castiel
s1: Castiel
s2: Castiel
s3: Castiel
s4: Castiel is perpect!
s5: Tell a joke: Castiel is perpect!
*s == s3
*s2 >= s3
delete: 0x7ffeefbff548
*s < SQString("abc")
s5.at(2): l
s5[5]: a
s5.c_str(): Tell a joke: Castiel is perpect!
sizeof(SQString) : 8
delete: 0x100419ad0
delete: 0x100404b60
delete: 0x100403f40
delete: 0x7ffeefbff558
delete: 0x7ffeefbff568
delete: 0x7ffeefbff570
Program ended with exit code: 0

使用起来还是如此的自然, 当然, 自实现只是让我们更好的了解本质, 并不是要使用自实现的东西, 而重复造轮子炫技.

const

接下来, 我们来说说const, const这个东西非常的厉害, 比如 int const * a, 和 int * const a就是完全两个概念, 这在上一篇文章里也有说到了, 这次我们来看下const在类中的表述.

struct A
{
public:
    A(int x, int y, int & z):_x(x), _y(y), _z(z) {
        cout<<"const x: "<<_x<<endl;
        cout<<"      y: "<<_y<<endl;
        cout<<"      z: "<<_z<<endl;
    }
private:
    const int _x;
    int _y;
    int & _z;
};

int main(int argc, const char * argv[]) {
    
    int z = 300;
    A a(100, 200, z);
    
    return 0;
}
const x: 100
      y: 200
      z: 300
Program ended with exit code: 0

在类中const与 初始化列表的使用, 可以使用初始化列表为const变量初始化.

int add(int & a, int & b) {
    return a + b;
}

int add(const int & a, const int & b) {
    return a + b;
}

int main(int argc, const char * argv[]) {

    int a = 3; int b = 5;
    cout<<add(a, b)<<endl;
    cout<<add(4, 6)<<endl;
    
    return 0;
}
8
10
Program ended with exit code: 0

使用const可以在传递参数的时候, 重载常量引用.

class A {
public:
    A(int x, int y):_x(x), _y(y) {}
    void foo();
    void foo() const;
private:
    int _x;
    int _y;
};

void A::foo() {
    _x = 300;
    cout<<"non-const : "<<_x<<_y<<endl;
}
void A::foo() const {
    cout<<"const: "<<_x<<_y<<endl;
}

int main(int argc, const char * argv[]) {

    const A a(3, 4);
    a.foo();
    
    A a1(5, 6);
    a1.foo();

    return 0;
}
const: 34
non-const : 3006
Program ended with exit code: 0

总结一下:

const修饰函数以后, 承诺, 不改变, 在本函数不会发生改变数据成员的行为.

const构成的重载函数, 非const对象, 优先调用非const版本.

const 对象, 只能调用const版本的函数. 很多库常见提供两个版本.

const 修饰的对象, 其内可以有非const数据成员, 但不可修改. 只能调用const 成员函数.

static

接下来, 我们来说说static, static是全局的存储在代码段的rw段, 我们平时的场景比如在 cell的标识符的引用, static const代替宏, gcd单例 等等.

class A {
    
public:
    int _m = 0, _n = 0;
    static int _share;
};
int A::_share = 100;

int main(int argc, const char * argv[]) {

    A a;
    cout<<a._n<<endl;
    cout<<a._m<<endl;
    cout<<a._share<<endl;
    cout<<A::_share<<endl;
    
    return 0;
}
0
0
100
100
Program ended with exit code: 0

static 修饰数据成员, 需要初始化, 不可以类内初始化.

类外初始化, 需要类名空间, 且不需要static.

static声明的数据成员, 不占用类的大小, 存储在data rw段.

class A {
    
public:
    ~A();
    void foo();
    int _m = 0, _n = 0;
    static int _fooCount;
};

int A::_fooCount = 0;

A::~A() {
    cout<<"dealloc"<<endl;
}

void A::foo() {
    cout<<"void foo()"<<endl;
    _fooCount++;
}

int main(int argc, const char * argv[]) {

    {
        A a,b,c;
        a.foo();
        b.foo();
        c.foo();
    }
    cout<<A::_fooCount<<endl;
    
    return 0;
}
void foo()
void foo()
void foo()
dealloc
dealloc
dealloc
3
Program ended with exit code: 0
class A {
    
public:
    ~A();
    void foo();
    static int invokeFooCount();
private:
    int _m = 0, _n = 0;
    static int _fooCount;
};

int A::_fooCount = 0;

A::~A() {
    cout<<"dealloc"<<endl;
}

void A::foo() {
    cout<<"void foo()"<<endl;
    _fooCount++;
}

int A::invokeFooCount() {
    return _fooCount;
}

int main(int argc, const char * argv[]) {

    {
        A a,b,c;
        a.foo();
        b.foo();
        c.foo();
        
        cout<<a.invokeFooCount()<<endl;
    }
    cout<<A::invokeFooCount()<<endl;
    
    return 0;
}

void foo()
void foo()
void foo()
3
dealloc
dealloc
dealloc
3
Program ended with exit code: 0

static修饰函数, 目的为管理静态变量.

class University {
public:
    University(string t, string l);
    static string & getLib();
    void display();
private:
    string _tower;
    string _lake;
    static string _lib;
};

string University::_lib = "";

University::University(string t, string l):_tower(t), _lake(l){}

string & University::getLib() {
    return _lib;
}
void University::display() {
    cout<<"tower: "<<_tower<<" lake: "<<_lake<<" lib: "<<_lib<<endl;
}

int main(int argc, const char * argv[]) {

    University u1("tower1", "lake1");
    University u2("tower2", "lake2");
    University u3("tower3", "lake3");

    University::getLib() += "lib1";
    u1.display();

    u2.getLib() += "lib2";
    u2.display();

    u3.getLib() += "lib3";
    u3.display();
    
    return 0;
}
tower: tower1 lake: lake1 lib: lib1
tower: tower2 lake: lake2 lib: lib1lib2
tower: tower3 lake: lake3 lib: lib1lib2lib3
Program ended with exit code: 0

static 共享

静态成员函数, 只能访问静态的成员. (数据成员和函数成员), 不能访问非静态的成员. 是因为非静态函数没有隐式传入this指针.

非静态函数访问静态函数式可以的.

singleton

单例, 这个非常简单, 对于有经验的iOS开发者来说, 其实就会写一个单例的宏, 但我们还是要知道如何实现.

class Singleton {
public:
    static Singleton * shareInstance();
    static void releaseInstance();
private:
    Singleton(){};
    ~Singleton(){};
    Singleton(const Singleton & another){};
    Singleton & operator=(const Singleton & another){return *this;};
    static Singleton * _instance;
};

Singleton * Singleton::_instance = nullptr;

Singleton * Singleton::shareInstance() {
    if (_instance == nullptr) {
        _instance = new Singleton;
    }
    return _instance;
}

void Singleton::releaseInstance() {
    if (_instance != NULL) {
        delete _instance;
        _instance = nullptr;
    }
}

int main(int argc, const char * argv[]) {

    Singleton * ps = Singleton::shareInstance();
    Singleton * ps2 = Singleton::shareInstance();
    Singleton * ps3 = Singleton::shareInstance();

    cout<<ps<<endl;
    cout<<ps2<<endl;
    cout<<ps3<<endl;
    
    Singleton::releaseInstance();
    
    return 0;
}
0x100412a60
0x100412a60
0x100412a60
Program ended with exit code: 0

总结就是静态读取, 私有构造.

自实现 autoreleasepool

自动释放池这个概念对于我们做iOS的并不会陌生吧, 接下来, 我们就来自实现一个简版的自动释放池, 当然这个版本并不会有引用计数的内容, 仅仅是内存托管的实现.

#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;

class SQObject {
public:
    SQObject(){}
    static SQObject * create() {
        SQObject * obj = new SQObject();
        if (obj && obj->init()) {
            obj->autoRealease();
            return obj;
        } else {
            delete obj;
            obj = nullptr;
            exit(-1);
        }
    }
    bool init() {
        cout<<"initial"<<endl;
        ch = rand()%(127-32) + 33;
        return true;
    }
    void autoRealease() {
//        if (head == nullptr) {
//            head = this;
//            this->next = nullptr;
//        } else {
//            this->next = head;
//            head = this;
//        }
        this->next = head;
        head = this;
    }
    
    static void autoRealeasePool() {
        SQObject * t = head;
        while (t) {
            cout<<"realease: "<<t->ch<<endl;
            t = t->next;
        }
    }
    
private:
    static SQObject * head;
    SQObject * next;
    char ch;
};

SQObject * SQObject::head = nullptr;

int main(int argc, const char * argv[]) {

    srand(time(NULL));
    for (int i = 0; i < 5; i++) {
        SQObject * obj = SQObject::create();
    }
    SQObject::autoRealeasePool();
    return 0;
}
initial
initial
initial
initial
initial
realease: n
realease: .
realease: ^
realease: i
realease: k
Program ended with exit code: 0

其实就和我们感觉上一样, 自动释放池用一个链表就可以解决, 当出了作用域的时候后, 将自动释放池链表中引用计数为0的地址给赋值null就完成了, 真是easy~

static const

这个我就不多说了, 大家日常使用都会有心得的东西.

class A {
public:
    static const int a = 100;
};

int main(int argc, const char * argv[]) {

    cout<<A::a<<endl;
    return 0;
}

static const 存储在数据段的 ro段;

pointer2class -> ivar & func

这一章会比较晦涩难懂些, 可以翻阅一下其他的文章, 其实就是如何通过指针来指向类内的成员变量及函数.

class Student {
public:
    Student(string n, int nu):name(n), num(nu){}
    void display(int idx) {
        cout<<"idx "<<idx<<" name "<<name<<" num "<<num<<endl;
    }
    //private:
    string name;
    int num;
};

int main(int argc, const char * argv[]) {

    Student s("Castiel", 1024);
    Student * ps = &s;
    
    Student ss("Aquas", 3328);
    Student * pss = &ss;
    
    string Student::* psn = &Student::name;
    cout<<s.*psn<<endl;
    cout<<ps->*psn<<endl;

    cout<<ss.*psn<<endl;
    cout<<pss->*psn<<endl;
    
    void (Student::* pf)(int) = &Student::display;
    (s.*pf)(1);
    (ss.*pf)(2);
    (ps->*pf)(3);
    (pss->*pf)(4);

    return 0;
}
Castiel
Castiel
Aquas
Aquas
idx 1 name Castiel num 1024
idx 2 name Aquas num 3328
idx 3 name Castiel num 1024
idx 4 name Aquas num 3328
Program ended with exit code: 0

关注void (Student::* pf)(int) = &Student::display;string Student::* psn = &Student::name; 就可以了, 编译器固定格式.

科里化

通过上述的指针, 我们还可以实现科里化, 也就是喵神100tips中的第一章内容的本质.

struct Point {
    int add(int x, int y) {
        return x + y;
    }
    int minus(int x, int y) {
        return x - y;
    }
    int mul(int x, int y) {
        return x * y;
    }
    int div(int x, int y) {
        return x / y;
    }
};

int oper(Point & p, int (Point::*pf)(int x, int y), int x, int y) {
    return (p.*pf)(x, y);
}

typedef int (Point::*PF)(int, int);

int main(int argc, const char * argv[]) {
    
    Point p;
    PF pf = &Point::add;
    pf = &Point::mul;
    cout<<oper(p, pf, 5, 2)<<endl;
    
    return 0;
}
10
Program ended with exit code: 0
隐蔽接口

更高级点的做法, 我们可以使用这个方法来隐藏接口, 这样别人在用我们做好的功能的时候, 就能傻瓜式的操作, 而隐蔽内部逻辑了.

class Game {
public:
    Game() {
        pf[0] = &Game::a;
        pf[1] = &Game::b;
        pf[2] = &Game::c;
        pf[3] = &Game::d;
    }
    void select(int i) {
        if (i >= 0 && i <= 3) {
            (this->*pf[i])(i);
        }
    }
private:
    void a(int idx){cout<<"void a(int idx)"<<idx<<endl;}
    void b(int idx){cout<<"void b(int idx)"<<idx<<endl;}
    void c(int idx){cout<<"void c(int idx)"<<idx<<endl;}
    void d(int idx){cout<<"void d(int idx)"<<idx<<endl;}
    enum {
        nc = 4
    };
    void (Game::*pf[nc])(int idx);
};

int main(int argc, const char * argv[]) {
    
    Game g;
    g.select(1);
    g.select(2);
    g.select(3);
    
    return 0;
}
void b(int idx)1
void c(int idx)2
void d(int idx)3
Program ended with exit code: 0

friend

友元, 其实就是一种便捷访问非本类私有方法的. 是对封装的破坏.

class Sprite {
    friend void fight(Sprite & sp);
public:
    Sprite(int lb = 100): _lifeBlood(lb){}
    int getLifeBlood() {
        return _lifeBlood;
    }
    void setLifeBlood(int lb) {
        _lifeBlood = lb;
    }
private:
    int _lifeBlood;
};

void fight(Sprite & sp) {
//    sp.setLifeBlood(sp.getLifeBlood() - 20);
//    cout<<sp.getLifeBlood()<<endl;
    sp._lifeBlood = sp._lifeBlood - 20;
    cout<<sp._lifeBlood<<endl;
}

int main(int argc, const char * argv[]) {
    
    Sprite sp;
    fight(sp);
    
    return 0;
}

class Complex {
    friend Complex operator+(Complex & c1, Complex & c2);
public:
    Complex(double r = 0, double i = 0): real(r), image(i) {}
    void dumpFormat() {
        cout<<"("<<real<<","<<image<<")"<<endl;
    }
private:
    double real;
    double image;
};

Complex operator+(Complex & c1, Complex & c2) {
    Complex c;
    c.real = c1.real + c2.real;
    c.image = c1.image + c2.image;
    return c;
}

int main(int argc, const char * argv[]) {
    
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex sum;
    sum = c1 + c2;
    sum.dumpFormat();
    
    return 0;
}

声明为谁的友元, 就可以通过谁的对象, 访问谁的私有函数.

class Point {
    friend float getDistance(Point & p1, const Point & p2);
public:
    Point(int x = 0, int y = 0):_x(x), _y(y){}
    void dumpFormat() {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
private:
    float _x;
    float _y;
};

float getDistance(const Point & p1, const Point & p2) {
    float dx = p1._x - p2._x;
    float dy = p1._y - p2._y;
    return sqrt(dx * dx + dy * dy);
}

int main(int argc, const char * argv[]) {
    
    Point p1(3, 4);
    p1.dumpFormat();
    Point p2(7, 8);
    p2.dumpFormat();
    
    cout<<"dis:"<<getDistance(p1, p2)<<endl;
    
    return 0;
}

全局做friend 不受类的权限控制

class Point;

class ManagePoint {
public:
    float getDistance(Point & p1, const Point & p2);
};

class Point {
    friend float ManagePoint::getDistance(Point & p1, const Point & p2);
public:
    Point(int x = 0, int y = 0):_x(x), _y(y){}
    void dumpFormat() {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
private:
    float _x;
    float _y;
};

float ManagePoint::getDistance(const Point & p1, const Point & p2) {
    float dx = p1._x - p2._x;
    float dy = p1._y - p2._y;
    return sqrt(dx * dx + dy * dy);
}

int main(int argc, const char * argv[]) {
    
    Point p1(3, 4);
    p1.dumpFormat();
    Point p2(7, 8);
    p2.dumpFormat();
    
    ManagePoint mp;
    cout<<"dis:"<<mp.getDistance(p1, p2)<<endl;
    
    return 0;
}

前向声明的问题 前向声明, 是一种不完全类型的声明, 不能定义对象.

可以定义指针和引用 作参数和返回值, 仅用在函数声明中.

class Point {
    friend class ManagePoint;
public:
    Point(int x = 0, int y = 0):_x(x), _y(y){}
    void dumpFormat() {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
private:
    float _x;
    float _y;
};

class ManagePoint {
public:
    float getDistance(const Point & p1, const Point & p2) {
        float dx = p1._x - p2._x;
        float dy = p1._y - p2._y;
        return sqrt(dx * dx + dy * dy);
    }
};

int main(int argc, const char * argv[]) {
    
    Point p1(3, 4);
    p1.dumpFormat();
    Point p2(7, 8);
    p2.dumpFormat();
    
    ManagePoint mp;
    cout<<"dis:"<<mp.getDistance(p1, p2)<<endl;
    
    return 0;
}
class Point {
    friend class ManagePoint;
public:
    Point(int x = 0, int y = 0):_x(x), _y(y){}
    void dumpFormat() {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
private:
    float _x;
    float _y;
};

class ManagePoint {
public:
    float getDistance(const Point & p1, const Point & p2) {
        float dx = p1._x - p2._x;
        float dy = p1._y - p2._y;
        return sqrt(dx * dx + dy * dy);
    }
    float getArea(const Point & p1, const Point & p2, const Point & p3) {
        float da = getDistance(p1, p2);
        float db = getDistance(p2, p3);
        float dc = getDistance(p3, p1);
        float p = (da + db + dc) / 2;
        return sqrt(p * (p - da) * (p - db) * (p - dc));
    }
};

int main(int argc, const char * argv[]) {
    
    Point p1(3, 4);
    p1.dumpFormat();
    Point p2(7, 8);
    p2.dumpFormat();
    Point p3(-100, 900);

    ManagePoint mp;
    cout<<"dis:"<<mp.getDistance(p1, p2)<<endl;
    cout<<"area:"<<mp.getArea(p1, p2, p3)<<endl;
    
    return 0;
}

友元类的使用, 可以避免前向声明的麻烦, 仅仅是提供便捷.

operator

运算符重载的使用, 和上篇一样, 这里更加深入.

class Complex {
public:
    Complex(double r = 0, double i = 0):real(r), image(i){}
    void dumpFormat() {
        cout<<"("<<this->real<<","<<this->image<<")"<<endl;
    }
    Complex & operator= (const Complex & another) {
        this->real = another.real;
        this->image = another.image;
        return *this;
    }
    const Complex operator+(const Complex & another) {
        Complex sum;
        sum.real = this->real + another.real;
        sum.image = this->image + another.image;
        return sum;
    }
private:
    double real;
    double image;
};

int main(int argc, const char * argv[]) {
    
    Complex a(1, 2), b(4, 5);
    Complex s = a + b;
    b.dumpFormat();
    a.dumpFormat();
    s.dumpFormat();
    
    return 0;
}
class Complex {
public:
    Complex(double r = 0, double i = 0):real(r), image(i){}
    void dumpFormat() {
        cout<<"("<<this->real<<","<<this->image<<")"<<endl;
    }
    Complex & operator +=(const Complex & another) {
        this->real += another.real;
        this->image += another.image;
        return *this;
    }
private:
    double real;
    double image;
};

int main(int argc, const char * argv[]) {
    
    int a = 10, b = 20, c = 30;
    a += b;
    b += c;
    cout<<"a: "<<a<<endl;
    cout<<"b: "<<b<<endl;
    cout<<"c: "<<c<<endl;

    Complex ca(10, 0), cb(20, 0), cc(30, 0);
    ca += cb; // plus return *this
    cb += cc;
    ca.dumpFormat();
    cb.dumpFormat();
    cc.dumpFormat();
    
    int a1 = 10, b1 = 20, c1 = 30;
    a1 += b1 += c1;
    cout<<"a1: "<<a1<<endl;
    cout<<"b1: "<<b1<<endl;
    cout<<"c1: "<<c1<<endl;
    
    Complex ca1(10, 0), cb1(20, 0), cc1(30, 0);
    ca1 += cb1 += cc1; // plus const
    ca1.dumpFormat();
    cb1.dumpFormat();
    cc1.dumpFormat();
    
    int a2 = 10, b2 = 20, c2 = 30;
    (a2 += b2) += c2;
    cout<<"a2: "<<a2<<endl;
    cout<<"b2: "<<b2<<endl;
    cout<<"c2: "<<c2<<endl;
    
    Complex ca2(10, 0), cb2(20, 0), cc2(30, 0);
    (ca2 += cb2) += cc2; // plus &
    ca2.dumpFormat();
    cb2.dumpFormat();
    cc2.dumpFormat();
    return 0;
}
a: 30
b: 50
c: 30
(30,0)
(50,0)
(30,0)
a1: 60
b1: 50
c1: 30
(60,0)
(50,0)
(30,0)
a2: 60
b2: 20
c2: 30
(60,0)
(20,0)
(30,0)
Program ended with exit code: 0
class Complex {
public:
    Complex(double r = 0, double i = 0):real(r), image(i){}
    void dumpFormat() {
        cout<<"("<<this->real<<","<<this->image<<")"<<endl;
    }
    const Complex operator-() const {
        return Complex(-this->real, -this->image);
    }
    
private:
    double real;
    double image;
};

int main(int argc, const char * argv[]) {
    
    int n = 5;
//    -n = 10;
    cout<<-n<<endl;
    cout<<n<<endl;
    cout<<-(-n)<<endl;

    Complex c(5, 0);
    Complex c1 = -c;
//    -cc = Complex(10, 0); //plus const
    Complex c2 = -(-c); //plus func const
    c1.dumpFormat();
    c.dumpFormat();
    c2.dumpFormat();
    
    return 0;
}
-5
5
5
(-5,-0)
(5,0)
(5,0)
Program ended with exit code: 0
class Complex {
public:
    Complex(double r = 0, double i = 0):real(r), image(i){}
    void dumpFormat() const {
        cout<<"("<<this->real<<","<<this->image<<")"<<endl;
    }
    Complex & operator++() {
        this->real++;
        this->image++;
        return *this;
    }
    const Complex operator++(int) /*编译器的规则*/ {
        Complex r(*this);
        ++this->real;
        ++this->image;
        return r;
    }
    
private:
    double real;
    double image;
};

int main(int argc, const char * argv[]) {
    
    int a = 10;
    cout<<++a<<endl;
    cout<<a<<endl;
    cout<<++++a<<endl;
    cout<<a<<endl;
    cout<<a++<<endl;
    cout<<a<<endl;
//    cout<<a++++<<endl;

    Complex c(10, 0);
    (++c).dumpFormat();
    c.dumpFormat();
    (++++c).dumpFormat();
    c.dumpFormat();
    (c++).dumpFormat();
    c.dumpFormat();
    
    return 0;
}
11
11
13
13
13
14
(11,1)
(11,1)
(13,3)
(13,3)
(13,3)
(14,4)
Program ended with exit code: 0
class Mail {
    friend class Sender;
public:
    Mail(string title, string contents):_title(title), _contents(contents){}
private:
    string _title;
    string _contents;
};


class Sender {
public:
    Sender(string addr):_addr(addr){}
    Sender & operator<<(const Mail & mail) {
        cout<<mail._title<<endl;
        cout<<mail._contents<<endl;
        return *this;
    }
private:
    string _addr;
};


int main(int argc, const char * argv[]) {
    
    Sender sender("github.com/coderzsq");
    Mail mail("title1", "description1");
    Mail mail2("title2", "description2");
    sender<<mail<<mail2;
    
    return 0;
}
title1
description1
title2
description2
Program ended with exit code: 0
class Complex {
public:
    Complex(double r = 0, double i = 0):real(r), image(i){}
    friend istream & operator>>(istream & ci, Complex & c) {
        ci>>c.real;
        ci>>c.image;
        return ci;
    }
    friend ostream & operator<<(ostream & co, Complex & c) {
        co<<"("<<c.real<<","<<c.image<<")"<<endl;
        return co;
    }
    
private:
    double real;
    double image;
};

int main(int argc, const char * argv[]) {

    Complex c, c1;
    cin>>c>>c1;
    cout<<c<<c1;
    return 0;
}
1 2
3 4
(1,2)
(3,4)
Program ended with exit code: 0

custom type conversion

自动类型转换, 其实就是一个单参数构造函数而已, 没有什么神奇的.

class Point3D;

class Point2D {
    friend class Point3D;
public:
    Point2D(int x = 0, int y = 0):_x(x), _y(y){}
    operator Point3D(void);
private:
    int _x;
    int _y;
};

class Point3D {
    friend class Point2D;
public:
    Point3D(int x = 0, int y = 0, int z = 0):_x(x), _y(y), _z(z){}
    explicit Point3D(const Point2D & d2) {
        this->_x = d2._x;
        this->_y = d2._y;
        this->_z = rand()%100;
    }
    void dumpFormat() {
        cout<<"("<<_x<<","<<_y<<","<<_z<<")"<<endl;
    }
private:
    int _x;
    int _y;
    int _z;
};

Point2D::operator Point3D(void) {
    return Point3D(this->_x, this->_y, rand()%100);
}

Point3D convert(Point2D d2) {
    return Point3D(d2);
}

int main(int argc, const char * argv[]) {

    srand((unsigned)time(0));
    Point2D d2(10, 100);
    Point3D d3 = static_cast<Point3D>(d2);
//    Point3D d3 = (Point3D)d2;
//    d3 = convert(d2);
    d3.dumpFormat();
     
    return 0;
}

functor

仿函数, 看似比较高级的应用, 其本质只不过和运算符从冲裁的本质是调用函数一样.

class Pow {
public:
    double operator() (double x, int y) {
        int ret = 1;
        for (int i = 0; i < y; i++) {
            ret *= x;
        }
        return ret;
    }
};

int main(int argc, const char * argv[]) {

    int a = 5;
    cout<<pow(a, 5)<<endl;
    Pow mypow;
    mypow(a, 2);
    cout<<mypow(a, 5)<<endl;

    return 0;
}
bool myCompare(int a, int b) {
    return a < b;
}

class Compare {
public:
    Compare(bool b = true):flag(b){}
    bool operator() (int a, int b) {
        if (flag == true) {
            return a > b;
        } else {
            return a < b;
        }
    }
private:
    bool flag;
};

int main(int argc, const char * argv[]) {

    int arr[6] = {1, 3, 5, 8, 6, 4};
    vector<int> vi(arr, arr + 6);
#if 0
    //method1
    vector<int>::iterator itr;
    for (itr = vi.begin(); itr != vi.end(); ++itr) {
        cout<<*itr<<endl;
    }
    //method2
    for (auto itr = vi.begin(); itr != vi.end(); ++itr) {
        cout<<*itr<<endl;
    }
    //method3
    for (auto i:vi) {
        cout<<i<<endl;
    }
#endif
    
    sort(vi.begin(), vi.end(), myCompare);
    for (auto i:vi) {
        cout<<i<<endl;
    }
    
    sort(vi.begin(), vi.end(), Compare(false));
    for (auto i:vi) {
        cout<<i<<endl;
    }
    
    return 0;
}

smart pointer

智能指针, 类似于自动释放池? 出了作用域后自动释放堆内存.

class A {
public:
    A() {
        cout<<"A()"<<endl;
    }
    void xxxx() {
        cout<<"xxxx"<<endl;
    }
    ~A() {
        cout<<"~A()"<<endl;
    }
};

class SmartPtr {
public:
    SmartPtr(A * pa) {
        _pa = pa;
    }
    A & operator*() {
        return *_pa;
    }
    A * operator->() {
        return _pa;
    }
    ~SmartPtr() {
        delete _pa;
    }
private:
    A * _pa;
};

void foo() {
#if 0
    A a;
    A * p = new A;
    delete p;
    
    auto_ptr<A> p(new A);
    p->xxxx();
    (*p).xxxx();
#endif
    
    SmartPtr sp(new A);
    sp->xxxx();
    (*sp).xxxx();
}

int main(int argc, const char * argv[]) {

    foo();
    return 0;
}
A()
xxxx
xxxx
~A()
Program ended with exit code: 0

memory customization

主要用于内存定制, 其实感觉没什么太大的意义, 封装的使用吧..

class A {
public:
    A() {
//        _x = 100;
//        _y = 200;
        cout<<"A()"<<endl;
    }
    void xxxx() {
        cout<<_x<<_y<<endl;
    }
    ~A() {
        cout<<"~A()"<<endl;
    }
    void *operator new(size_t size) {
        cout<<"operator new"<<endl;
        cout<<size<<endl;
        void * p = malloc(size);
        ((A*)p)->_x = 100;
        ((A*)p)->_y = 200;
        cout<<p<<endl;
        return p;
    }
    void operator delete(void * p) {
        cout<<"operator delete"<<endl;
        cout<<p<<endl;
    }
    void * operator new[](size_t size) {
        cout<<"operator new[]"<<endl;
        cout<<size<<endl;
        void *p = malloc(size);
        cout<<p<<endl;
        return p;
    }
    void operator delete[] (void * p) {
        cout<<"operator delete[]"<<endl;
        cout<<p<<endl;
        free(p);
    }
private:
    int _x;
    int _y;
};

int main(int argc, const char * argv[]) {
#if 0
    A * pa = new A;
    pa->xxxx();
    delete pa;
#endif
    A * pa = new A[10];
    delete[] pa;
    return 0;
}
operator new[]
88
0x10291f740
A()
A()
A()
A()
A()
A()
A()
A()
A()
A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
~A()
operator delete[]
0x10291f740
Program ended with exit code: 0

最后

更多新鲜文章可以关注并Star, 我们一起学习.

GitHub Repo:coderZsq.github.io
Follow: coderZsq · GitHub

最近的文章

Swift 第二梯队iOS面试败北感悟

GitHub Repo:coderZsq.target.swiftFollow: coderZsq · GitHubResume: https://coderzsq.github.io/coderZsq.webpack.js/#/日常扯淡从去年开始, 我就一直有尝试的面试些大公司, 因为对于一个半路出家(非计算机专业), 靠着MJ视频入门的iOS菜鸡玩家, 经过了3年的摸爬滚打, 终于也渐渐的可以做一些简单的前端, 后端, 移动端的交互, 但想要继续深入就感觉瓶颈越发的明显, 基础的薄...…

移动开发继续阅读
更早的文章

C++ 一把窥探OC底层的利刃

GitHub Repo:coderZsq.github.ioFollow: coderZsq · GitHubResume: https://coderzsq.github.io/coderZsq.webpack.js/#/日常扯淡作为iOS开发的菜鸡, 平日里的工作就是做业务, 调UI, 对于我们这种弱鸡玩家来说, 编程呢, 其实就是调方法, 调属性, 调库…但光是做业务UI的工作肯定会让自己日渐乏味, 为了不重复写那些看了想吐的代码, 去年就花了点时间写了一个代码生成工具, 用于配...…

移动开发继续阅读