0
点赞
收藏
分享

微信扫一扫

安全开发实战(1)--Cdn

艾晓雪 2024-04-20 阅读 12

汇编语言

汇编语言与机器语言一一对应,每一条机器语言都有与之对应的汇编指令

  • 汇编语言可以通过汇编得到机器语言
  • 机器语言可以通过反汇编得到汇编语言

一:new和delete的编译器转化

​ 有一个复数类:class complex { public: complex(double a,double b); private: double real; double imag; };

new

则:complex* pc=new complex(1,2);

编译器对new进行以下的操作:

  1. 首先进行内存分配
void* mem=operator new(sizeof(complex));
  1. 其次对指针类型转化
pc=static_cast<complex*>(mem)
  1. 调用构造函数
pc->complex::complex(1,2);

delete

delete pc;

编译器所做的工作:

  1. 调用析构函数
complex::~complex(pc);
  1. 释放内存
operator delete(pc)

总结:

new是先申请内存,再调用构造函数

delete是先调用析构函数,再释放内存

删除数组用delete[]

String* p=new String[3];//指针数组
delete[] p;

二:复习String类

class String{
public:
    // 构造函数--最好用inline提高效率
    inline String(const char *str = 0){
        if (str == 0){
            data = new char[1];
            data[0] = '\0';//*data='\0'
        }
        else{
            data = new char[strlen(str) + 1];
            strcpy(data, str);//目的,源头
        }
    }
    // 拷贝构造
    String(const String &str){
        data = new char[strlen(str.data) + 1];
        strcpy(data, str.data);
    }
    // 赋值构造---返回值本来就存在不,是在函数内创建,用&
    String &operator=(const String &str){
        // 不可以自我赋值
        if (this == &str)//指针地址相同
            return *this;
        //赋值是接收端本来就存在,所以需要清除原来内容
        delete[] data;
        data = new char[strlen(str.data) + 1];
        strcpy(data, str.data);
        return *this;//有返回值可以连串赋值:a=b=c
    }
    // 析构函数
    inline ~String(){
        delete[] data;
    }
    //输入输出辅助函数
    char *get_data() const { return data; }
private:
    char *data; // 动态分配字符指针
};

最需要注意的就是赋值构造

  1. 首先考虑返回值和传入参数:
  • 传入参数:类对象的引用

  • 返回值:类对象,由于=右边是提前存在的,用&

  1. 其次注意一定要先释放目标端(=左边)的所有内容然后重新分配空间
        delete[] data;
        data = new char[strlen(str.data) + 1];
  1. 最后注意自我赋值,也就是a=b中,a和b的字符数组指针不可以相同
       if (this == &str)//指针地址相同
            return *this;
//输入输出辅助函数
    char *get_data() const { return data; }
//定义:String的输出
ostream& operator<<(ostream& os,String s){
    os << s.get_data();//接收端是字符指针
    return os;
}

三:拷贝构造函数

浅拷贝

class Rect{
public:
    Rect() { p = new int(100); }
    ~Rect() {
        cout << "析构函数" << endl;
        if(p){
            delete p;
        }
    }
    void setp(int x) { *p = x; }
    int getp() const { return *p; }
private:
    int *p;
};
int main(){
    Rect a;
    Rect b(a);
    b.setp(920);
    cout << a.getp() << "," << b.getp() << endl;
    b.setp(320);
    cout << a.getp() << "," << b.getp() << endl;
}

深拷贝

class Rect{
public:
    Rect() { p = new int(100); }
    Rect(const Rect& r) {
        p = new int[1];
        *p = *(r.p);
    }
    ~Rect() {
        cout << "析构函数" << endl;
        if(p){
            delete p;
        }
    }
    void setp(int x) { *p = x; }
    int getp() const { return *p; }
private:
    int *p;
};
int main(){
    Rect a;
    Rect b(a);// Rect b=a;
    a.setp(200);
    cout << a.getp() << "," << b.getp() << endl;
    a.~Rect();
    b.setp(100);
    cout << b.getp() << endl;
}

小结

拷贝有两种:深拷贝,浅拷贝。

  • 当出现类的等号赋值时,会调用拷贝函数,在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。

当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象。所以这时必须采用深拷贝。

四:static

static修饰函数中变量或者类中的变量

​ 当变量被声明为静态时,会在内存的静态变量区为其分配空间,变量值会存活在程序的生命周期内。

int test(){
    static int i = 0;//在函数test中定义静态变量i
    i++;
    return i;
}
int main(){
    for (int i = 0; i < 5;i++)
        cout << test() << " ";
    return 0;
}

类中的静态变量仅在单独的静态存储中分配空间时初始化一次,类中的静态变量由类对象共享

class demo{
public:
    static int i;//在demo中定义静态变量
    static char c;
    demo(){}
};
/*静态变量初始化必须在类外实现*/
int  demo::i=100;
char demo::c = 'a';

一个类改变了值,其他类都会受影响

int main(){
    demo aa;
    demo bb;
    aa.c = '*';
    bb.i = 400;
    cout <<aa.c<<","<<bb.c<<endl;
    cout <<aa.i<<","<<bb.i<<endl;
    cout << demo::i << "," << demo::c << endl;
    return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

static修饰的类函数只能访问静态变量

class demo{
public: 
    demo(){}
    static void get_Info(){
        cout << i << "," << c << endl;
    }
private:
    static int i;//在demo中定义静态变量
    static char c;
};
/*静态变量初始化必须在类外实现*/
int  demo::i=100;
char demo::c = 'a';
int main(){
    demo aa;
    demo bb;
    aa.get_Info();
    bb.get_Info();
    //更建议使用
    demo::get_Info();
    return 0;
}

static修饰类成员对象

静态类对象:就像变量一样,声明为静态的对象也具有直到程序生命周期为止的作用域

#include <iostream>
#include <cstring>
using namespace std;
class demo{
public:
    demo(string s):s(s) { cout << "construct fun " <<s<<endl; }
    ~demo() { cout << "delete fun " <<s<< endl; }
private:
    string s;
};
int main(){
    int x = 1;
    if(x==1){
    static demo bb("bb");
    }
    if(x==1){
    demo aa("aa");
    }
    return 0;
}

stactic内存

class complex{
public:
    complex(double re):re(re) {}
    double real() const { return re; }
private:
    double re;
};
int main(){
    complex c1(2.3), c2(3.2), c3(4.6);
    cout<<c1.real()<<endl;    
    cout<<c2.real()<<endl;
    cout<<c3.real()<<endl;    
}

其实在执行:c.real()时候:编译器的形式为:

    cout<<complex::real(&c1)<<endl;    
    cout<<complex::real(&c2)<<endl;
    cout<<complex::real(&c3)<<endl; 

也就是说编译器默认有一个参数是对象的地址,这个也就是this指针

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 静态数据只有一份所有类公用
  • 非静态函数只有一份,但是每个对象都有自己的数据内存,所以只能通过this指针来找到相应数据存储区域

五:单例模式

单例模式具有如下特点:

  • 一个类只有一个实例化对象
  • 全局可以使用
class single{
public:
    //返回静态成员,所有用static,对象存在返回值用&
    static single& getInstance(){
        return tar;
    }
    void print(){
        cout << "success!" << endl;
    }
private:
    //三个构造函数
    single(){}
    single(const single& x){}
    single &operator=(const single &x) { return *this; }
    //静态类对象
    static single tar;
};
single single::tar;//静态成员声明
int main(){
    single::getInstance().print();
}

这个方式直接创建了类对象,如果不需要使用会造成资源浪费,最好是:使用时创建

class single{
public:
    //返回静态成员,所有用static,对象存在返回值用&
    static single& getInstance();
    
    void print(){
        cout << "ok!" << endl;
    }
private:
    //三个构造函数
    single(){}
    single(const single& x){}
    single &operator=(const single &x) { return *this; }
};
single& single::getInstance() {
     //在调用时候创建
     static single tar;
     return tar;
};
int main(){
    single::getInstance().print();
}

上述其实对应类单例模式的两种类型:

懒汉模式: 当你的应用程序在需要调用返回类对象()方法的时候才创建实例化的对象,类似于懒加载

​ 这种方式的好处在于,有一些单例模式的实例,可能在整个进程的声明周期内可能不一定用到。那么这种懒汉模式就省去了不必要的资源创建过程。

饿汉模式一般的实现方式为:在进程或者模块加载的时候就会创建全局的实例。

单例模式释放资源

class signlePattern{
public:
    //函数对外接口
    static signlePattern* getInstance(){
        /*加上一句判断*/
        if(point==NULL){
            point = new signlePattern();
        }
        return point;
    }
    //析构私有成员函数
    static void releaseSource(){
        if(point){
            delete point;
            point = NULL;
        }
        cout << "finish" << endl;
    }
    void test() {
        cout << "has called!" << endl;
    }

private:
    //三个函数
    signlePattern(){}
    signlePattern(const signlePattern& x){}
    signlePattern &operator=(const signlePattern &x) { return *this; }
    //静态成员对象--提前创建
    static signlePattern *point;
};
//静态独享成员声明
//创建对象
signlePattern *signlePattern::point = new signlePattern;
int main(){
    signlePattern::getInstance()->test();
    signlePattern::releaseSource();
}

六:模板

类模板

class complex{
public:
    complex(T r=0,T i=0):re(r),im(i){};
    T real() const { return re; }
    T imag() const { return im; }
private:
    T re, im;
};
int main(){
    complex<int> c1(3, 6);
    complex<double> c2(1.2, 3.4);
    cout << c1.real()<< "," << c1.imag() << endl;
    cout << c2.real() << "," << c2.imag() << endl;
}

函数模板

class cmp{
public:
    cmp(int h=0,int w=0):h(h),w(w){};
    //重载运算符<
    bool operator<(const cmp& x) const{
        return h + w < x.h + x.w;
    }
    void getInfo(){
        cout << h << "," << w << endl;
    }
private:
    int h,w;
};
//函数模板
template<typename T>
const T& Min(const T& a,const T& b){
    return a < b ? a : b;
}
int main(){
    cmp a(3, 2);
    cmp b(2, 1);
    cmp c= Min(a, b);
    c.getInfo();
}

七:面向对象编程

1:复合关系:composition

列子:自定义一个队列类,类中存在一个双端队列成员,然后利用deque的几个函数完成普通队列功能

#include <queue>
using namespace std;
template<class T>
class MYqueue{
private:
    deque<T> dq;
public:
    void push(const T &x) { dq.push_back(x); }
    void pop() { dq.pop_front(); }
    int size() const { return dq.size(); }
    T &front() { return dq.front(); }
    T &back() { return dq.back(); }
};

内存角度

点和距离例子

点类

class point {
public:
    //构造函数
    point(int x, int y) : x(x), y(y) { cout << "point构造函数" << endl; }
    //拷贝构造
    point(const point& tmp) :x(tmp.x), y(tmp.y) {
        cout << "point拷贝构造函数" << endl;
    }
    //返回成员
    int getX() const { return x; }
    int getY() const { return y; }
private:
    int x, y;
};

距离类

class Distance {
public:
    //构造函数
    Distance(point, point);
    //返回dist
    double getDist() const { return dist; }

private:
    point a, b;
    double dist;
};
Distance::Distance(point a, point b) :a(a), b(b) {
    cout << "distance构造函数" << endl;
    double x = double(a.getX() - b.getX());
    double y = double(a.getY() - b.getY());
    dist = sqrt(x * x + y * y);
}

主程序:

int main(){
    point aa(0, 3);
    point bb(4, 0);
    Distance cc(aa, bb);
    cout << cc.getDist() << endl;
}
三角锥和三角形
class triangle{
public:
    triangle(int a,int b):a(a),b(b){}
    triangle(const triangle& x):a(x.a),b(x.b){}
    double square() const { return (1.0 / 2) * a * b; }
private:
    int a, b;
};
class triPyramid{
public:
    triPyramid(int a,int b,int h):t(a,b),h(h){}
    triPyramid(triangle t,int h):t(t),h(h){}
    double tiji() const { return (1.0) / 3 * t.square() * h; }

private:
    triangle t;
    int h;
};
int main(){
    triangle aa(2, 3);
    triPyramid m(aa, 6);//triPyramid(triangle t,int h)
    triPyramid n(2, 4, 6);//triPyramid(int a,int b,int h)
    cout << aa.square() << endl;
    cout << m.tiji()<<","<<n.tiji()<<endl;
}
构造函数和析构函数的顺序

class A{};

class B{ private:A a};

  • 构造由内而外:(套娃)

  • 析构由外而内:(打碎套娃)

class point {
public:
    //构造函数
    point(int x, int y) : x(x), y(y) { cout << "point构造函数" << endl; }
    //拷贝构造
    point(const point& tmp) :x(tmp.x), y(tmp.y) {
        cout << "point拷贝构造函数" << endl;
    }
   //析构函数
    ~point() { cout << "point析构函数" << endl; }
private:
    int x, y;
};
class Distance {
public:
    Distance(int aa, int bb, int cc, int dd) :a(aa, bb), b(cc, dd) {
        cout << "distance构造函数" << endl;
    }
    ~Distance() {
        cout << "Distance析构函数" << endl;
    }
private:
    point a, b;
};
int main() {
    Distance cc(0,3,4,0);
}

在这里插入图片描述

class A{
public:
    A(int x) : x(x) { cout << "A构造函数" << endl; }
    ~A() { cout << "A析构函数" << endl; }
    void show() { cout << x << endl; }
private:
    int x;
};
class B{
public:
   B(int a,int b,int c):a(a),b(b),y(c){
       cout << "B构造函数" << endl;
   }
   ~B() { cout << "B析构函数" << endl; }
   A geta() const { return a; }
   A getb() const { return b; }
   void show() { cout << y << endl; }
   private:
   A a, b;
   int y;
};
int main(){
    B x(10, 20, 30);
    x.geta().show();
    x.getb().show();
    x.show();
}

2:委托 composition by reference

说白了就是:一个类存在另一个类的指针

例子:

class Car
{
    Engine engine; // 成员对象
    Wing * wing;   // 成员指针对象
};

定义一辆汽车,所有的汽车都有 engine,但不一定都有 wing,所以wing 只占一个指针

类对象和类指针
  • 类对象: 类名 a;在定义之后就已经为a这个对象分配了内存,且为内存栈,是个局部的临时变量
  • 类指针: 类名 *b = new 类名();在定义*b的时候并没有分配内存,只有执行new后才会分配内存,且为内存堆,是个永久变量,除非你释放它。

3:继承Inheritance

  • 构造函数由内而外(先子类后父类)

  • 析构函数由外而内(先父类再子类)

注意----析构函数要想保证先子类析构,后父类析构,那么:父类的析构函数必须是virtual

例子:

class doucument{
public:
    doucument(const char *s){
        name = new char[strlen(s) + 1];
        strcpy(name, s);
    }
    doucument(const doucument &s){
        name = new char[strlen(s.name) + 1];
        strcpy(name, s.name);
    }
    void showName() { cout << name << endl; }
private:
    char *name;
};
class Book:public doucument{
public:
    Book(const char* name,double p):doucument(name),price(p){}
    Book(const doucument& x,double p):doucument(x),price(p){}
    void show() {
        showName();
        cout << price<< endl; }
private:
    double price;
};
int main()
{
    doucument mm("hello");
    Book n1("good", 19.9);
    Book n2(mm, 29.9);
    n1.show();
    n1.show();
}

4:虚函数

  • 非虚函数(non-virtual)
  • 虚函数(virtual)
  • 纯虚函数(pure virtual)
class shape{
public:
 //纯虚函数
 //因为子类形状对父类不可知,所以父类无法预设,只能子类自己实现
    virtual void drow() const=0;//virtual =0
 //虚函数
 //设计成虚函数是,如果子类想要打印更细致的错误信息,子类可以自己实现   
    virtual void error(const string& msg);
  //非虚函数
  //因为不管子类是什么(三角形,矩形),给对象生成编号的动作是一致的,父类可以实现
    int objectID() const;
};
打开文件

父类提供打开文件的函数,对所有文件来说:查找,搜索,关闭这些动作一样,只有:读取文件内容不同

所以:父类打开文件函数提供一个虚函数读取文件,这个函数由子类实现

简单实现:

class cDocument{
public:
    void onFileOpen(){
        cout << "check file status!" << endl;
        cout << "open file !" << endl;
        serialize();//子类重载虚函数
        cout << "close file !" << endl;
        cout << "update file view!" << endl;
    }
    virtual void serialize() =0;
};
class cMydoc:public cDocument{
public:
    void serialize(){
        cout << "my file" << endl;
    }
};
int main(){
    cMydoc mydoc;
    mydoc.onFileOpen();
}

八:复合和继承同时出现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有两种:

  • 父类存在其他类,子类继承了父类

  • 子类继承了父类,子类存在其他类

子类继承父类,存在其他类对象

//假设类B继承类A,类B中有类C对象
class A{
public:
    A(int a):a(a) {
        cout << "构造函数A()" << endl;
    }
    ~A() { cout << "析构函数~A()"<<endl; }
    void getA() { cout <<"A::"<<a << endl; }
private:
    int a;
};
class C{
public:
    C(char ch):ch(ch){
        cout << "构造函数C()" << endl;
    }
    ~C() { cout << "析构函数~C()" << endl; }
    void getC() { cout <<"C::"<<ch << endl; }
private:
    char ch;
};
class B:public A{
public:
    B(int a,char ch,double x):A(a),obj(ch),x(x) {
        cout << "构造函数B()" << endl;
    }
    B(char ch,int a,double x):obj(ch),A(a),x(x) {
        cout << "构造函数B()" << endl;
    }
    ~B() { cout << "析构函数~B()" << endl; }
    C getOBJ() const { return obj; }
    void getB() { cout <<"B::"<<x << endl; }
private:
    C obj;
    double x;
};

运行结果:

构造顺序是首先调用继承的父类,其次调用组合中的实例对象,最后才是构造自己本身

父类存在其他类,子类继承

//类B中有类C对象,类A继承类B
class C{
public:
    C(char ch):ch(ch){
        cout << "构造函数C()" << endl;}
    ~C() { cout << "析构函数~C()" << endl; }
    void getC() { cout <<"C::"<<ch << endl; }
private:
    char ch;
};
class B{
public:
    B(char ch,double x):obj(ch),x(x) {
        cout << "构造函数B()" << endl;}
    ~B() { cout << "析构函数~B()" << endl; }
    C getOBJ() const { return obj; }
    void getB() { cout <<"B::"<<x << endl; }
private:
    C obj;
    double x;
};
class A:public B{
public:
    A(int a,char c,double b):a(a),B(c,b){
        cout << "构造函数A()" << endl;
    }
    ~A() { cout << "析构函数~A()"<<endl; }
    void getA() { cout <<"A::"<<a << endl; }
private:
    int a;
};

析构先自己,再复合或构造

举报

相关推荐

0 条评论