C++学习总结——类和对象(一)

简介: C++学习总结——类和对象(一)



一、class和struct

1、在其中可以同时定义成员变量成员函数

struct person
{
public:
    void Init()
    {
        cout<<"zdl"<<endl;
    }
    void fun(int _age, char _name)
    {
        age = _age;
        name = _name;
        cout<<this->age<<endl;
    }
private:
    int age;
    char name;
};
class person
{
public:
    void Init()
    {
        cout<<"zdl"<<endl;
    }
private:
    int age;
    char name;
};

小函数:想成为inline,直接在类里定义即可。

大函数:应该声明和定义分离。定义时要加作用域,表明属于哪个类域。


2、访问限定符class默认访问权限为私有,struct默认访问权限为公有

(1)public(公有):类内类外都可以访问。

(2)protected(保护):类内可以访问,类外不能访问。

(3)private(私有):类内可以访问,类外不能访问。


3、类的实例化

类是对对象进行描述的,是一个模型一样的东西。用类类型创建对象的过程,称为类的实例化。person类是没有空间的,只有实例化出的对象才有具体的空间。比如:一个房子的设计图,就像是一个类。你在上海根据设计图建了房子,在北京根据设计图建了同样的房子,这就叫类的实例化。

person p1;//类的实例化

实例化的每个对象的成员变量存储在类中,且都有自己独立的空间,是不同的变量。但是每个对象,调用类的成员函数都是同一个,编译链接时根据函数名去公共代码区找到函数的地址,call函数地址。且类不计函数大小。


4、this指针(是一个形参)

1、this指针在栈区,成员函数有一个隐式形参 类名*const this   只能在成员函数内部使用。

2、this指针本质上是成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给

this形参。所以对象中不存储this指针

3、 this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传

递,不需要用户传递。


5、构造函数(一般写成全缺省的)

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证

每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任

并不是开空间创建对象,而是初始化对象

其特征如下:

1、 函数名与类名相同。

2、无返回值。

3、对象实例化时编译器自动调用对应的构造函数。(即可以不显示地自己调用)

4、构造函数可以重载。

class Date
{
public:
    Date(int year=1, int month=1, int day=1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
        int _year;
        int _month;
        int _day;
};
int main()
{
    Date d1;
    Date d2(2023, 6, 5);
    Date d3(2023, 3);
    return 0;
}

注:默认生成构造函数:对内置类型成员不做初始化(因此我们要自己写构造函数)。自定义类型成员(class和struct)可以自动调用默认构造函数(它自己的构造函数)。

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。


6、析构函数

与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

* 内置类型动态开辟的空间(malloc,new等)——显示写析构函数。

* 内置类型非动态开辟的空间——不需要显示写析构函数。编译器的默认析构函数就可以解决。

* 自定义类型成员会去调用它自己的析构函数,所有不需要显示写。如用两个栈实现队列的题中。队列类中不需要写析构函数,Stack成员会去调用它自己的析构函数。

* 先定义的后析构,后定义的先析构。

class A
{
    //...
};
A aa3(3)
void f()
{
    Static A aa0(0);
    A aa1(1);
    A aa2(2);
    static A aa4(4);
}
int main()
{
    f();
    f();
}

构造顺序:3、0、1、2、4、1、2。静态变量在程序结束后才会销毁,所以第二次调用了f()后,静态变量就不用再次调用构造函数了。

析构顺序:~2、~1、~2、~1、~4、~0、~3。


7、拷贝构造函数

只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

 

1、拷贝构造函数是构造函数的一个重载形式。

2、 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,

因为会引发无穷递归调用。

class Data
{
public:
    Data(const Data &d)
    {
        _year = d.year;
        _month = d.month;
        _day = d.day;
    }
private:
    _year;
    _month;
    _day;
}
Data d2(d1);

若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按

字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。(内置类型和自定义类型均可以)

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定

义类型是调用其拷贝构造函数完成拷贝的。


8、深拷贝和浅拷贝

浅拷贝:默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

但是,如果在被拷贝的对象中有动态开辟的成员变量,如动态开辟的数组。在浅拷贝后,新的对象的该成员变量会指向和被拷贝对象相同的空间。这样在调用析构函数时,就会被析构两次。

所以我们就需要自己实现深拷贝来解决这个问题。(后面专门讲解)


9、运算符重载(operator)

内置类型可以直接使用运算符运算,编译器知道要如何运算。

自定义类型不可以直接使用运算符运算,编译器不知道要如何运算。

赋值运算符重载格式:

参数类型:const T&,传递引用可以提高传参效率。

返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值。

检测是否自己给自己赋值。

返回*this :要复合连续赋值的含义。

//判断两个日期是否相等
class Date
{ 
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    bool operator==(const Date& d)
    {
        return _year == d._year
        && _month == d._month
        && _day == d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};

如:用栈实现队列的题中,MyQueue中的成员变量的类型是自定义类型Stack,默认生成的赋值重载函数就可以用。前提是Stack中有正确的赋值重载函数。这样就可以自动调用。

任何一个类,只需要写一个 >  == 或者 <  ==重载,剩下的比较运算符重载复用即可。


Data& operator++() //前置,返回++后的
{
    *this += 1;
    return *this;
}
Data  operator++(int) //后置,返回++前的
{
    Data tmp(*this);
    *this += 1;
    return tmp;
}
目录
相关文章
|
8天前
|
C++
C++(十一)对象数组
本文介绍了C++中对象数组的使用方法及其注意事项。通过示例展示了如何定义和初始化对象数组,并解释了栈对象数组与堆对象数组在初始化时的区别。重点强调了构造器设计时应考虑无参构造器的重要性,以及在需要进一步初始化的情况下采用二段式初始化策略的应用场景。
|
8天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
8天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
8天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。
|
8天前
|
存储 C++
C++(五)String 字符串类
本文档详细介绍了C++中的`string`类,包括定义、初始化、字符串比较及数值与字符串之间的转换方法。`string`类简化了字符串处理,提供了丰富的功能如字符串查找、比较、拼接和替换等。文档通过示例代码展示了如何使用这些功能,并介绍了如何将数值转换为字符串以及反之亦然的方法。此外,还展示了如何使用`string`数组存储和遍历多个字符串。
|
17天前
|
存储 C++
C++ dll 传 string 类 问题
C++ dll 传 string 类 问题
15 0
|
29天前
|
C++ 容器
C++中自定义结构体或类作为关联容器的键
C++中自定义结构体或类作为关联容器的键
30 0
|
30天前
|
存储 算法 搜索推荐
【C++】类的默认成员函数
【C++】类的默认成员函数
|
29天前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
21天前
|
存储 算法 编译器
c++--类(上)
c++--类(上)