c++类学习过程中的一些知识点

类的语法形式

class 类名称
{
public:
    公有成员(外部接口)
private:
    私有成员
protected:
    保护型成员
};

公有成员:类与外部的接口,任何外部函数都可以访问类内的公有数据类型和函数
私有成员:只允许本类的对象里的成员访问
保护成员:在继承和派生上与私有成员有轻微差别
成员变量:类里定义的变量,可以在类里所有的函数里使用这些变量
本地变量:函数里定义的变量

class A
{
private:
    int a;
public:
    int Fun();
};
int A::Fun()
{
    int fun;
    a=1;
    fun=2;
    return fun;
}

成员变量: a
本地变量: fun
2.隐藏指针

class A
{
private:
    int a;
public:
     void f();
};
void A::f()
{
   a=1;
}
struct B
{
    int a;
};
void f(struct B *p)
{
    p->a=1;
}
int main()
{
    A a;
    B a;
    a.f();
    f(&a);
    return 0;
}

这里的a.f()和f(&a)是一样的,进入f这个函数的时候编译器会自动加上This指针。
函数会变成这样。这样就可以区分是哪一个对象了。

void A::f()
{
   This->a=1;
}

类的构造与析构
c++中类里定义的变量在定义对象的时候所指向的内存并不是干净的(java不是这样的),这是由于c++为了提高效率,类里的变量既然要用到就一定要给它赋值,没必要提前清理一遍,所以我们需要在类的构造函数里把类初始化。
相应的,类似于指针,使用完后需要释放其内存,对象也是如此,用构造函数创建对象后,程序负责跟踪该对象,直到其过期为止,对象过期时,程序将自动调用一个特殊的成员函数——析构函数

class X
{
    int i;
public:
    X();
    ~X();
};

这个X()就是构造函数。
(1)构造函数的名字和类的名字相同
(2)构造函数是没有返回类型的(不能加返回类型,构造函数里不能加return)
(3)一个对象被创造的时候其对应的类里的构造函数就会被执行(也就是说如果有 X a的时候实际上会去做 a.X())
(4)如果构造函数有参数的话,定义一个对象的时候要加参数 如:X a(1)

这个~X()就是析构函数
(1)析构函数在出对象作用域的时候被执行。

4.c++的动态分配内存
在这里插入图片描述malloc分配的内存要用free来释放,同样的new分配的内存要用delete来释放
delete[] p的意思是释放掉int 数组大小的空间,如果不加[]的话只会释放单个int大小的空间,在释放空间的时候析构函数就会被执行。
5. struct 和 class 的区别

两者区别在于

class A
{
    int a;
    int b;
public:
    int c;
};
struct A
{
    int a;
    int b;
public:
    int c;
};

在类里没有限制访问属性的部分,class会将其视为private,而struct 会将其视为public.

6.初始化
初始化方法一:类内初始化

class A
{
    int a=0;
public:
};

类内初始化顺序晚于构造函数
初始化方法二:直接在构造函数里进行初始化

class A
{
    int *p;
public:
    A()
    {
        p=NULL;
    }
};

初始化方法二:在构造函数括号后加上冒号给出要初始化变量的名字,再加一个括号,在括号里加上初始化变量的值。

#include<bits/stdc++.h>
using namespace std;
class point
{
public :
    void initpoint(double x=0,double y=0)
    {
        this->x=x;
        this->y=y;
    }
    double getX(){return x;}
    double getY(){return y;}
private:
    double x,y;
};
int main()
{
    point a;
    a.initpoint(1,2);
    cout<<a.getX()<<a.getY()<<endl;
}

这里的double x=0,和double y=0是可以这样写的,如果在调用initpoint函数的时候没有给参数,x和y就会被初始化为0,如果给了参数,x和y就是参数那个值

函数缺省参数值

c++允许我们 在函数参数表里预先给一个参数初始化一个值
比如 fun(int size,int initquantity = 0 );
fun(1);这样写是合法的
但是要注意 fun(int a=1,int b=2,int c)这样是不对的,必须从右边往左初始化,但是这种写法只能写在声明里

const
const int * p和int const *p 都是指p指向的数据是常数,不可以通过p来修改它所指向内存的数据
int *const p 是指指针是不能改变的,不能进行p++等操作,但是可以通过p来修改它所指向内存的数据

const的数据不能赋给非const的指针
非const的数据 可以赋给const的指针
怎么来理解呢?
在语法上 可以通过非const的指针来修改 它所指向的值,但是如果它指向的那个值是个const定义的常数,语法就冲突了,所以const的数据不能赋给非const的指针,因此语法规定了const 类型的指针来保存const数据

子类对象可以当作父类对象用
父类对象里面有的,子类对象都有,因此子类对象可以成为父类对象成员函数的参数,子类对象里多出来的东西相当于不存在。所以在子类使用复制构造函数的 时候,父类的复制构造函数的参数可以是子类对象的目标对象(要复制的那个对象)

虚函数表

#include<iostream>
using namespace std;
class A
{
    int i;
public :
    A():i(10){}
    virtual void f(){cout<<"A::f()"<<i<<endl;}
};
class B:public A
{
    int j;
public:
    B():j(20){}
    virtual void f(){cout<<"B::f()"<<j<<endl;}
};
int main()
{
    A a;
    B b;
    A *p=&b;
    p->f();

    a=b;
    p=&a;
    p->f();
    return 0;
}

输出结果
在这里插入图片描述
我们用A类型的指针指向对象b,然后执行f函数,会执行b的,因为虚函数表没有改变,所以当我们把b的值赋给a的时候,由于虚函数表没有改变,我们在执行
p->f()的时候,执行的是A类的f函数

int main()
{
    A a;
    B b;
    A *p=&a;
    int* r=(int*)&a;
    int* t=(int*)&b;
    *r = *t;
    p->f();
    return 0;
}

虚函数表的地址位于类的起始地址紧接着的地址
如果我们把主函数改成这样
输出结果会变成这样在这里插入图片描述也就是说赋值的过程,不会改变虚函数表的地址
但是如果是 A a, B b,然后 b=a,这样的话,执行 b->f()就会执行A::f了
在这里插入图片描述对象中的常数据成员只能通过初始化列表的形式来初始化
常对象无法调用非const成员函数。
若必须要修改常对象里面的数据成员,可以在数据成员前面加上mutable
如 mutable int x

在这里插入图片描述不能用初始化列表来初始化静态成员变量

发布了37 篇原创文章 · 获赞 3 · 访问量 2390

猜你喜欢

转载自blog.csdn.net/Stillboring/article/details/104398544