C++知识点

1、直接使用结构体做为参数

struct sclass            
{            
    int a;        
    int b;        
};            
int Plus(int a,int b)            
{            
    return a+b;        
}            
            
int main(int argc, char* argv[])            
{            
    sclass s;        
    s.a = 10;        
    s.b = 20;        
            
    int x = Plus(s.a,s.b);        
            
    printf("%d\n",x);        
    return 0;        
}            

总结:

将结构体直接做为参数传递的时候,传递的是整个结构体.

反汇编:

sub esp,10h
mov eax,esp
mov ecx,dword ptr [ebp-10h]
mov dword ptr [eax],ecx
mov edx,dword ptr [ebp-0Ch]
mov dword ptr [eax+4],edx
mov ecx,dword ptr [ebp-8]
mov dword ptr [eax+8],ecx
mov edx,dword ptr [ebp-4]
mov dword ptr [eax+0Ch],edx
call @ILT+35(Plus) (00401028)
add esp,10h

2、传递结构体指针

struct sclass            
{            
    int a;        
    int b;        
    int c;        
    int d;        
};            
int Plus(sclass* sc)            
{            
    return sc->a+sc->b;        
}            
int main(int argc, char* argv[])            
{            
    sclass s;        
    s.a = 10;        
    s.b = 20;        
            
    int x = Plus(&s);        
            
    printf("%d\n",x);        
    return 0;        
}            

反汇编:

mov dword ptr [ebp-10h],0Ah
mov dword ptr [ebp-0Ch],14h
lea eax,[ebp-10h]
push eax
call @ILT+40(Plus) (0040102d)
add esp,4

3、函数可以放在结构体里面,也可以放在结构体外面

struct sclass                
{                
    int a;            
    int b;            
    int c;            
    int d;            
                
    int Plus(sclass* sc)            
    {            
        return sc->a+sc->b;        
    }            
};                
                

探测:通过sizeof来探测将函数放在里面与外面结构体的大小有什么变化?

4、函数放在里面如何使用的问题 观察反汇编:

struct sclass                
{                
    int a;            
    int b;            
    int c;            
    int d;            
                
    int Plus(sclass* sc)            
    {            
        return sc->a+sc->b;        
    }            
};                
                
int main(int argc, char* argv[])                
{                
    sclass s;            
    s.a = 10;            
    s.b = 20;            
                
    int x = s.Plus(&s);            
                
    printf("%d %x\n",x,sizeof(s));            
    return 0;            
}                
                

注意观察反汇编:

1、参数传递

2、堆栈平衡

有没有发现什么问题?

 

5、封装、类、成员函数

    struct sclass                
    {                
        int a;            
        int b;            
        int c;            
        int d;            
                    
        int Plus()            
        {            
            return a+b;        
        }            
    };                
                    
    int main(int argc, char* argv[])                
    {                
        sclass s;            
        s.a = 10;            
        s.b = 20;            
                    
        int x = s.Plus();            
                    
        printf("%d %x\n",x,sizeof(s));            
                    
        return 0;            
    }                

封装:

1、将函数定义到结构体内部,就是封装.

2、编译器会自动传递结构体的指针给函数.

类:

带有函数的结构体,称为类.

成员函数:

结构体里面的函数,称为成员函数.


 6、什么是this指针?

struct sclass            
{            
    int a;        
    int b;        
    int c;        
    int d;        
            
    int Plus()        
    {        
        return a+b;    
    }        
};            
            
            
sclass s;            
            
s.Plus();            

观察反汇编:

lea ecx,[ebp-10h]
call @ILT+90(Plus) (0040105f)

this指针的特点:

1、你用或者不用,它就在那里

2、参数个数确定的时候,用ecx来传递

3、参数个数不确定的时候,最后一个传递(参见不定长参数)

4、this指针不能做++ -- 等运算,不能重新被赋值.

5、this指针不占用结构体的宽度.

//显示使用this指针                
                
struct sclass                
{                
    int a;            
    int b;            
                
    void Init(int a,int b)            
    {            
        this->a = a;        
        this->b = b;        
    }            
    void Print()            
    {            
        printf("%d %d",a,b);        
    }            
                
};                
                
sclass s;                
                
s.Init(1,2);                
                
s.Print();                

 

7、构造函数

    struct Person            
    {            
        int age;        
        int level;        
        Person()        
        {        
            printf("Person对象创建了\n");    
        }        
        Person(int age,int level)        
        {        
            this->age = age;    
            this->level = level;    
        }        
        void Print()        
        {        
            printf("%d-%d\n",age,level);    
        }        
    };            
                

 

构造函数的特点:

1、与类同名

2、没有返回值

3、创建对象的时候执行

4、主要用于初始化

5、可以有多个(最好有一个无参的),称为重载 其他函数也可以重载

6、编译器不要求必须提供

 

8、析构函数

析构函数的特点:

1、只能有一个析构函数,不能重载

2、不能带任何参数

3、不能带返回值

4、主要用于清理工作

5、编译器不要求必须提供

    #include "malloc.h"            
                
    struct Person            
    {            
        int age;        
        int level;        
        char* arr;        
        Person()        
        {        
            printf("无参构造函数执行了...");    
        }        
        Person(int age,int level)        
        {        
            printf("有参构造函数执行了...");    
            this->age = age;    
            this->level = level;    
            arr = (char*)malloc(1024);    
        }        
        ~Person()        
        {        
            printf("析构函数执行了...");    
            free(arr);    
            arr = NULL;    
        }        
        void Print()        
        {        
            printf("%d-%d\n",age,level);    
        }        
    };            

 

9、继承

1、观察反汇编        
        
struct Person        
{        
    int age;    
    int sex;    
};        
struct Teacher        
{        
    int age;    
    int sex;    
    int level;    
    int classId;    
};        
struct Student        
{        
    int age;    
    int sex;    
    int code;    
    int score;    
};        
        
Teacher t;        
        
t.age = 1;        
t.sex = 2;        
t.level = 3;        
t.classId = 4;        
        
printf("%d\n",sizeof(t));        
        

观察反汇编:

mov dword ptr [ebp-10h],1
mov dword ptr [ebp-0Ch],2
mov dword ptr [ebp-8],3
mov dword ptr [ebp-4],4
push 10h
push offset string "%d\n" (0042201c)
call printf (004010e0)
add esp,8

Student s;        
        
s.age = 1;        
s.sex = 2;        
s.code = 3;        
s.score = 4;        
        
printf("%d\n",sizeof(s));        

mov dword ptr [ebp-10h],1
mov dword ptr [ebp-0Ch],2
mov dword ptr [ebp-8],3
mov dword ptr [ebp-4],4
push 10h
push offset string "%d\n" (0042201c)
call printf (004010e0)
add esp,8

    2、改变写法:        
            
            
    struct Person        
    {        
        int age;    
        int sex;    
    };        
    struct Teacher:Person        
    {        
        int level;    
        int classId;    
    };        
    struct Student:Person        
    {        
        int code;    
        int score;    
    };        
            
Teacher t;            
            
t.age = 1;            
t.sex = 2;            
t.level = 3;            
t.classId = 4;            
            
printf("%d\n",sizeof(t));            
            

观察反汇编:

mov dword ptr [ebp-10h],1
mov dword ptr [ebp-0Ch],2
mov dword ptr [ebp-8],3
mov dword ptr [ebp-4],4
push 10h
push offset string "%d\n" (0042201c)
call printf (004010e0)
add esp,8

Student s;        
        
s.age = 1;        
s.sex = 2;        
s.code = 3;        
s.score = 4;        
        
printf("%d\n",sizeof(s));        

mov dword ptr [ebp-10h],1
mov dword ptr [ebp-0Ch],2
mov dword ptr [ebp-8],3
mov dword ptr [ebp-4],4
push 10h
push offset string "%d\n" (0042201c)
call printf (004010e0)
add esp,8

总结: 

1、什么是继承?

继承就是数据的复制

2、为什么要用继承?

减少重复代码的编写

3、Person 称为父类或者基类

4、Teacher、Student称为子类或者派生类

5、t和s可以称为对象或者实例.

6、可以用父类指针指向子类的对象.

多层继承:        
        
struct X        
{        
    int a;    
    int b;    
};        
struct Y:X        
{        
    int c;    
    int d;    
};        
struct Z:Y        
{        
    int e;    
    int f;    
};        
        
        
Z z;        
        
z.a = 1;        
z.b = 2;        
z.c = 3;        
z.d = 4;        
z.e = 5;        
z.f = 6;        
        
printf("%d\n",sizeof(z));        
        
        
        
        
        
struct X        
{        
    int a;    
    int b;    
};        
struct Y:X        
{        
    int a;    
    int d;    
};        
struct Z:Y        
{        
    int e;    
    int f;    
};        
        
        
        
Z z;        
        
z.X::a = 1;        
z.b = 2;        
z.Y::a = 3;        
z.d = 4;        
z.e = 5;        
z.f = 6;        
        
printf("%d\n",sizeof(z));        
printf("%d\n",z.X::a);        
printf("%d\n",z.b);        
printf("%d\n",z.Y::a);        
printf("%d\n",z.d);        
printf("%d\n",z.e);        
printf("%d\n",z.f);        

观察反汇编:

mov dword ptr [ebp-18h],1
mov dword ptr [ebp-14h],2
mov dword ptr [ebp-10h],3
mov dword ptr [ebp-0Ch],4
mov dword ptr [ebp-8],5
mov dword ptr [ebp-4],6
push 18h
push offset string "%d\n" (0042201c)
call printf (004010e0)
add esp,8

 

多重继承:        
        
struct X        
{        
    int a;    
    int b;    
};        
struct Y        
{        
    int c;    
    int d;    
};        
struct Z:X,Y        
{        
    int e;    
    int f;    
};        
        
        
Z z;        
        
z.a = 1;        
z.b = 2;        
z.c = 3;        
z.d = 4;        
z.e = 5;        
z.f = 6;        
        
printf("%d\n",sizeof(z));        
        

3、继承的特性        
        
        
struct X        
{        
    int a;    
    int b;    
};        
struct Y        
{        
    int a;    
    int d;    
};        
struct Z:X,Y        
{        
    int e;    
    int f;    
};        
        
        
Z z;        
        
z.X::a = 1;        
z.b = 2;        
z.Y::a = 3;        
z.d = 4;        
z.e = 5;        
z.f = 6;        
        
printf("%d\n",sizeof(z));        
printf("%d\n",z.X::a);        
printf("%d\n",z.b);        
printf("%d\n",z.Y::a);        
printf("%d\n",z.d);        
printf("%d\n",z.e);        
printf("%d\n",z.f);        
        

观察反汇编:


mov dword ptr [ebp-18h],1
mov dword ptr [ebp-14h],2
mov dword ptr [ebp-10h],3
mov dword ptr [ebp-0Ch],4
mov dword ptr [ebp-8],5
mov dword ptr [ebp-4],6
push 18h
push offset string "%d %x\n" (0042201c)
call printf (004010e0)
add esp,8


总结:

一个子类可以有多个父类,即多重继承

观察反汇编:


mov dword ptr [ebp-18h],1
mov dword ptr [ebp-14h],2
mov dword ptr [ebp-10h],3
mov dword ptr [ebp-0Ch],4
mov dword ptr [ebp-8],5
mov dword ptr [ebp-4],6
push 18h
push offset string "%d %x\n" (0042201c)
call printf (004010e0)
add esp,8

总结:

1、多重继承增加了程序的复杂度,容易出错

2、微软建议使用单继承,如果需要多重继承可以改为多层继承


10、将定义与实现分离,代码会有更好的可读性

xxx.h 头文件中                
                
struct Test                
{                
    int x;            
    int y;            
    int z;            
                
    void Init(int x,int y,int z);            
    void Function1();            
    void Function2();            
    void Function3();            
};                
                
                
xxx.cpp                
                
void Test::Init(int x,int y,int z)                
{                
    this->x = x;            
    this->y = y;            
    this->z = z;            
}                
void Test::Function1()                
{                
    printf("Function1:%x\n",x);            
}                
void Test::Function2()                
{                
    printf("Function2:%x\n",y);            
}                
void Test::Function3()                
{                
    printf("Function3:%x\n",z);            
}                
                

特别说明:

1、xxx.h 只是一个文件,可以是任何的后缀名,如果你愿意,
可以叫xxx.exe

2、#include 的作用只是把里面的内容复制过来 仅此而已.

如:#include "abc.exe"

3、xxx.h 与 xxx.cpp并不要求一定同名

11、public private的使用

public的意思是,这个成员哪里都可以用,不用担心被修改,所以,一旦发布成public的成员,是不能够改名字的.

private的意思是,这个成员只用于内部使用,不要在其他的地方使用.

如下:                探测一:观察private成员是否有空间            
                            
struct Test                printf("%d\n",sizeof(Test));            
{                            
private:                探测二:直接使用private成员            
    int x;                        
public:                Test t;            
    int y;             t.x = 10;            
};                    t.y = 20;            
                            

总结:

1、对外提供的函数或者变量,发布成public的 但不能随意改动.

2、可能会变动的函数或者变量,定义成private的 这样编译器会在使用的时候做检测.

3、只有结构体内部的函数才可以访问private的成员.

4、public/private可以修饰函数也可以修饰变量.

private真的不能访问吗?

struct Test            
{            
private:            
    int x;        
public:            
    int y;        
    void Init(int x,int y)        
    {        
        this->x = x;    
        this->y = y;    
    }        
};            
                
Test t;            
t.Init(1,2);            
            
            
int* p = (int*)&t;            
            
int n = *p;            
            
int m = *(p+1);            
            
printf("%d %d\n",n,m);            
            

总结:

private修饰的成员与普通的成员没有区别 只是编译器会检测.

private修饰的成员只要自己的其他成员才能访问

1、成员权限的区别:                        
                        
class Base                        
{                        
    int x;                    
    int y;                    
};                        
                        
int main(int argc, char* argv[])                        
{                        
    Base base;                    
                        
    base.x = 10;                    
    base.y = 20;                    
                        
    return 0;                    
}                        
                        
                        
class与struct的区别:                        
                        
编译器默认class中的成员为private 而struct中的成员为public                        
                        
2、继承中的区别:            
            
            
class Base            
{            
public:            
    int x;        
    int y;        
};            
class Sub:Base            
{            
public:            
    int a;        
    int b;        
};            
int main(int argc, char* argv[])            
{            
    Sub sub;        
            
    sub.x = 1;  //无法访问        
    sub.y = 2;  //无法访问        
    sub.a = 3;        
    sub.b = 4;        
            
    return 0;        
}            
    class Sub:private Base    
    {    
    public:    
        int a;
        int b;
    };    
        
    父类中的程序继承后变成private属性    
        
    如果不希望改变成员的属性:    
        
    class Sub:public Base    
    {    
    public:    
        int a;
        int b;
    };    
private是否被继承            
            
            
class Base            
{            
public:            
    Base()        
    {        
        x = 11;    
        y = 12;    
    }        
private:            
    int x;        
    int y;        
};            
class Sub:Base            
{            
public:            
    int a;        
    int b;        
};            
            
int main(int argc, char* argv[])            
{            
    Sub sub;        
    sub.a = 1;        
    sub.b = 2;        
            
    int* p = (int*)⊂        
            
            
    printf("%d\n",sizeof(sub));        
    printf("%d\n",*(p+0));        
    printf("%d\n",*(p+1));        
    printf("%d\n",*(p+2));        
    printf("%d\n",*(p+3));        
            
    return 0;        
}            

总结:

1、父类中的私有成员是会被继承的

2、只是编译器不允许直接进行访问

 

 

转载于:https://www.cnblogs.com/louzi/p/11148721.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值