C++ 类和对象(中)

类和对象cpp 【类的成员函数和类的定义分开写】(截到人脸郭老师orz【注意这里的::表示不是全局函数,而是一个类的成员函数】 阅读详情

一、默认成员函数

在C++ 类和对象(上)中,我提到过空类,也就是什么成员都没有的类。但事实上,空类中真的什么都没有吗?并不是,在C++中,对于任意一个类,编译器都会为我们自动生成6个默认的成员函数(如果我们不显示地去声明)。这些函数在特定的情况下会被自动调用,但自动调用并不意味着它们能像用户所期望的那样能实现特定的功能或者完成特定的任务,更多的时候需要我们自己实现这些函数的功能。在这里插入图片描述

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

在使用C语言练习初阶数据结构,即线性表、链表、栈、队列、二叉树等内容时,大家可能经常会犯两个错误:

  1. 在使用数据结构创建变量时忘记对其进行初始化操作而直接进行插入等操作;
  2. 在使用完毕后忘记对动态开辟的空间进行释放而直接返回;

C++为了避免上面C语言存在的问题,设计出了默认成员函数,其中,构造函数和析构函数针对的是上面的两个问题,而其他四个函数则是适用了其他场景与需求。

二、构造函数

1. 基础知识

构造函数是一种特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的任务并不是创建对象,而是当对象被创建之后完成对象的初始化工作;同时构造函数不能由用户调用,而是在创建类类型对象时由编译器自动调用,并且在对象整个生命周期内只调用一次。

构造函数有如下特性:

  1. 函数名和类名相同;
  2. 无返回值,连 void 都没有
  3. 对象实例化时编译器自动调用对应的构造函数;
  4. 构造函数支持重载与缺省参数;
  5. 如果类中没有显式定义构造函数,C++编译器会自动生成一个无参的默认构造函数,但一旦用户显式定义,编译器将不再自动生成;
  6. 自动生成的无参构造函数对内置类型不处理,对自定义类型调用它自身的默认构造函数;
  7. 无参构造函数、全缺省构造函数、我们没写编译器自动生成的构造函数,都可以认为是默认构造函数。
class Date
{
public:
	Date()  //无参构造函数
	{
		_year = 1970;
		_month = 1;
		_day = 1;
	}

	Date(int year, int month = 1, int day = 1)  //带参构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;                //调用无参构造函数
	d1.Print();

	Date d2(2022, 10, 4);   //调用带参构造函数
	d2.Print();
}

在这里插入图片描述

可以看到,我们并没有显式地去调用构造函数,而是由编译器自动调用;

注意事项

  1. 构造函数虽然支持重载和缺省参数,但是无参构造函数和全缺省构造函数不能同时出现,因为在调用时会产生二义性

    在这里插入图片描述

    一般情况下我们只会显式定义一个全缺省的构造函数,因为全缺省的构造函数可以接收各种参数情况

  2. 当我们调用无参构造函数或者全缺省构造函数来初始化对象时,不要在对象后面带括号,因为这样编译器会把它当作函数声明

在这里插入图片描述

2. 特性分析:自动生成

构造函数的第五点特性是:如果类中没有显式定义构造函数,C++编译器会自动生成一个无参的默认构造函数,但一旦用户显式定义编译器将不再自动生成;下面我们来验证这个特性

class Date
{
public:
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;  //无参
	d1.Print();
}

可以看到上面的日期类中我们没有显式地定义构造函数,所以编译器应该会自己生成一个无参的默认构造函数完成初始化工作:

在这里插入图片描述

但是我们发现 d1对象中的_year, _month, _day仍然是随机值,默认的构造函数好像并没有完成初始化工作,看来编译器生成的默认构造函数并没有什么用,至于原因就在构造函数的第六个特性。

3. 特性分析:选择处理

C++ 把类型分成内置类型 (基本类型) 和自定义类型,内置类型就是语言本身提供的数据类型,如int/char/double/指针,自定义类型就是我们使用 class/struct/union 等自己定义的类型,如:Stack/Queue/Date;

构造函数的第六点特性是:自动生成的无参构造函数对内置类型不处理,对自定义类型调用它自身的默认构造函数;

对于这个特性,我们使用 Date、Stack 和 Myqueue 三个类来对比理解(Myqueue 即 用两个栈实现一个队列)

class Date
{
public:
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
class Stack
{
public:
	void Push(int x)
	{
		_a[_top++] = x;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	void Push(int x)
	{
		_pushST.Push(x);
	}

	Stack _pushST;
	Stack _popST;
};

当我们不显式定义构造函数时,编译器会自动生成一个无参的默认构造函数,但是对内置类型不处理,由于Stack 和 Date 的成员变量全部为内置类型,所以自动生成的构造函数在这里没有任何作用,必须我们手动定义自己的默认构造函数。

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == nullptr)
		{
			perror("malloc fail\n");
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}

	void Push(int x)
	{
		_a[_top++] = x;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

而对于 MyQueue 来说,它的成员变量全部为自定义类型,即使我们不提供构造函数,编译器自动生成的构造函数也会去调用自定义类型的默认构造函数,完成初始化的需求

在这里插入图片描述

总结

那么,到底什么时候需要我们自己定义构造函数,什么时候使用编译器默认生成的构造函数呢?答案是:面向需求 – 当编译器默认生成的构造函数就能满足我们的需求时我们就不需要自己提供构造函数,如MyQueue;当编译器提供的构造函数不能满足我们的需求时就需要我们自己定义,如Date/Stack;

4. C++11新特性

经过上面的学习我们发现,自动生成的默认构造函数对内置类型不处理,对自定义类型要处理的特性使得构造函数变得很复杂,因为大多数类都有需要初始化的内置类型成员变量,这就使得编译器默认生成的构造函数看起来没什么作用;

C++11 针对内置类型成员不初始化的缺陷,打了个补丁:内置类型成员变量在类中声明时可以给缺省值,意思就是如果构造函数没有对该成员变量进行初始化,那么该变量就会使用缺省值。

在这里插入图片描述

这里给成员变量缺省值并不是对其初始化,因为类中的成员变量只是声明,还没有定义,只有当实例化对象之后它才具有物理空间,才能进行初始化。

三、析构函数

1. 基础知识

和构造函数相反,析构函数完成对象中资源的清理工作,并且在对象销毁时由编译器自动调用(如同构造函数不是创建一个对象一样,析构函数也不是销毁一个对象,对象的销毁工作由编译器完成)。

析构函数的特性如下:

  1. 析构函数名是在类名前加上字符 ~ (表示与构造函数功能相反)
  2. 析构函数无参数无返回值;
  3. 析构函数不支持重载,一个类只能有一个析构函数,若未显式定义,系统会自动生成一个默认析构函数;
  4. 对象生命周期结束时,C++ 编译器会自动调用析构函数
  5. 自动生成的析构函数对内置类型不处理,对自定义类型调用它自身的析构函数
  6. 如果定义了多个对象,后定义的对象会被先析构。

在这里插入图片描述

2. 特性分析:选择处理

析构函数的选择处理和构造函数的一样,对内置类型不处理(本来除指针以外的内置类型就不需要清理),对自定义类型调用它自身的析构函数。

  1. 对于成员变量都是内置类型,没有申请资源的类 (malloc 内存、fopen 文件等操作),比如 Date 类,我们不用显式定义析构函数,直接使用编译器自动生成的构造函数即可;

  2. 对于申请了资源的类,比如 Stack 类(成员变量_a指向了一块动态开辟的空间),如果我们使用自动生成的析构函数,那么对内置类型 int* _a 就不会进行清理,造成内存泄露;所以我们需要显式定义析构函数;

  3. 对于成员变量都是自定义类型的类,比如 MyQueue,我们也不用显式定义析构函数,编译器会调用自定义类型的析构函数。

总结

如果类中没有申请资源,析构函数可以不写,直接使用编译器自动生成的默认析构函数,比如 Date 类;如果类中申请了资源,必须写析构函数,否则会造成资源泄漏,比如Stack类;其中自定义类型的成员变量一律看作没有申请资源。

四、拷贝构造

1. 基础知识

我们知道创建对象时,可以通过传值调用构造函数初始化对象,那能否通过传对象初始化一个与已存在对象一模一样的新对象呢?答案是可以的,C++设计了拷贝构造来实现这个功能,拷贝构造可以看作是构造函数的函数重载,参数是对象。

拷贝构造的特性如下:

  1. 拷贝构造函数的参数只有一个且必须是类类型对象的引用(一般常用 const 修饰),使用传值方式编译器直接报错,因为会引发无穷递归调用;
  2. 若未显式定义,编译器会自动生成默认的拷贝构造函数,在用已存在的类类型对象创建新对象时由编译器自动调用。
  3. 自动生成的拷贝构造函数对内置类型以字节为单位进行值拷贝(浅拷贝),相当于 memcpy ,对自定义类型调用其自身的拷贝构造函数
class Date
{
public:
	Date(int year = 1970, int month = 1, int day = 1) //构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(const Date& d)                     //拷贝构造
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
    Date d1;         //调用构造函数
    Date d2(d1);     //调用拷贝构造函数
    return 0;
}

2. 特性分析:引用传参

拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器会直接报错,因为会引发无穷递归调用。

原理如下:当我们使用 d1 来拷贝构造 d2 时,首先会传参,而传值传参时实参会拷贝一份给形参,也就是拷贝构造,编译器就会自动调用拷贝构造函数,调用拷贝构造函数的第一步又是传参,如此下去就会引发无穷递归;

在这里插入图片描述

但是如果拷贝构造函数的参数是引用的话,形参作为实参的别名,不需要拷贝,也就不会再自动调用拷贝构造函数,从而使得函数功能顺利实现;另外,拷贝构造函数的参数通常使用 const 修饰,这是为了避免在函数内部修改传进来的对象。

3. 特性分析:选择处理

编译器自动生成的拷贝构造函数对内置类型以字节为单位进行值拷贝(浅拷贝),对自定义类型调用其自身的拷贝构造函数。

值拷贝对于大部分类型都是可行的,但是对于指针类型就会引发错误,下面以Stack类为例:

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == nullptr)
		{
			perror("malloc fail\n");
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}

	~Stack()  
	{
		free(_a);
		_a = NULL;
		_top = _capacity = 0;
	}
    
	void Push(int x)
	{
		_a[_top++] = x;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

int main()
{
    Stack s1;
    Stack s2(s1);   //调用自动生成的拷贝构造函数
    return 0;
}

上面并没有显式定义 Stack 的拷贝构造函数,那么编译器会自动生成一个拷贝构造函数,把 s1 的内容按字节拷贝到 s2,看似没有任何问题,但是程序一运行就崩溃了,调试发现程序是在调用析构函数时崩溃的。

在这里插入图片描述

在这里插入图片描述

原来是因为 s1 和 s2 的成员变量 _a 指向了同一块空间,程序结束后这两个对象分别调用了两次析构函数对这块空间进行了释放,而这是不允许的。

在这里插入图片描述

浅拷贝在拷贝指针时,不仅不能正确地完成拷贝任务,还会造成程序崩溃,所以在拷贝有指针的对象时,不能依赖于自动生成的拷贝构造函数,而是应该自己手动定义具有深拷贝功能的拷贝构造函数,做法是为 s2 的 _a 单独开辟一块空间,并将 s1 中_a指向空间的内容拷贝到新空间中,其余内置成员变量再按字节拷贝

Stack(const Stack& st)  //拷贝构造
{
    _a = (int*)malloc(sizeof(int) * st._capacity);
    if (_a == nullptr)
    {
        perror("malloc fail\n");
        exit(-1);
    }
    memcpy(_a, st._a, sizeof(int) * st._capacity);
    _top = st._top;
    _capacity = st._capacity;
}

在这里插入图片描述

对于 MyQueue 类来说,它的成员变量全部是自定义类型,所以编译器会去调用其自身的拷贝构造函数,一如既往地不用我们操心。

在这里插入图片描述

总结

如果类中没有申请资源,拷贝构造可以不写,直接使用编译器自动生成的默认拷贝构造函数,比如 Date 类;如果类中申请了资源,必须写拷贝构造函数,否则就可能出现浅拷贝以及同一块空间被析构多次的情况,比如Stack类;其中自定义类型的成员变量一律看作没有申请资源。

拷贝构造和析构函数在资源管理方面有很大的相似性,可以认为这两个成员函数总是同时出现。

拷贝构造的三种使用场景:

  1. 使用已存在对象创建新对象
  2. 函数参数类型为类类型对象
  3. 函数返回值类型为类类型对象

五、运算符重载

对于 C/C++ 编译器来说,它知道内置类型的运算规则,比如整形 + 整形、指针 + 整形、浮点型 + 整形;但是它不知道自定义类型的运算规则,比如自定义的日期类的运算规则,日期 + 天数 、日期比较大小、日期 - 日期,这些编译器都不能自己计算,需要我们自己去定义相应的函数,比如 AddDay、SubDay,但是这些函数的可读性始终是没有 + - > < 这些符号的可读性高的,而且调用也不如运算符方便;

为了让自定义类型支持由运算符计算,C++为自定义类型引入了运算符重载,运算符重载是具有特殊函数名的函数 ,其函数名为关键字 operator + 需要重载的运算符符号,也具有返回值和参数列表。

下面以 Date 类的 += 运算符重载为例:

class Date
{
public:
	Date(int year = 1970, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//获取每个月的天数
	int GetMonthDay(int year, int month)
	{
		static int day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) //闰年
			return 29;
		return day[month];
	}

	//打印
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

    void operator+=(Date& d, int day)
    {
        d._day += day;
        while (d._day > GetMonthDay(d._year, d._month))
        {
            d._day -= GetMonthDay(d._year, d._month);
            d._month++;
            if (d._month > 12)
            {
                d._month -= 12;
                d._year++;
            }
        }
    }
    
private:
	int _year;
	int _month;
	int _day;
};

上面的实现看似没有问题,实则犯了一个很低级的错误,就是把对象的值也传进成员函数里面了。

在这里插入图片描述

程序报错说函数参数太多,因为一个 += 运算符共两个操作数,所以成员函数 operator+= 应该只能接收两个参数,第一个参数是隐含自动传递的 this 指针,第二个参数才是留给我们显式传递的 day。

//+= 运算符重载
void operator+=(int day)  //只传递右操作数,左操作数通过this指针自动传递
{
    _day += day;  
    while (_day > GetMonthDay(_year, _month))
    {
        _day -= GetMonthDay(_year, _month);
        _month++;
        if (_month > 12)
        {
            _month -= 12;
            _year++;
        }
    }
}

在这里插入图片描述

运算符重载函数有如下特性:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型操作数 (因为运算符重载只能对自定义类型使用);
  3. 运算符重载函数作为成员函数时,其形参看起来比操作数数目少1,是因为成员函数的第一个参数为隐藏的 this;
  4. 以下5个运算符不能重载: .* :: sizeof . ?:

特殊的运算符重载

在常见的运算符重载中,operator++ 和 operator-- 有一些特殊的地方。拿++举例,++ 分为前置++和后置++,二者如果都用运算符重载实现,除了返回值不同,其他都相同,这样的两个函数是不能构成函数重载的。所以C++规定:后置++/--重载时多增加一个int类型的参数,此参数由编译器自动传递,目的就是为了和前置 ++/--构成函数重载。

六、赋值重载

1. 基础知识

赋值运算符重载函数是C++的六个默认成员函数之一,它也是运算符重载的一种,它的作用是在两个已存在的对象之间进行赋值。

赋值运算符重载的特性如下:

  1. 赋值运算符只能重载成类的成员函数,不能重载成全局函数,毕竟这是六个默认成员函数之一。
  2. 若未显式定义,编译器会自动生成默认的赋值重载函数,并在两个已定义的对象之间进行赋值的时候自动调用。
  3. 自动生成的赋值重载函数对内置类型以字节为单位进行值拷贝(浅拷贝),对自定义类型调用其自身的赋值重载函数;

2. 特性分析:选择处理

赋值重载函数的选择处理特性和拷贝构造函数非常类似:自动生成的赋值重载函数对内置类型以字节为单位进行值拷贝,对自定义类型会去调用其自身的赋值重载函数。

对于没有申请资源的类来说,不用自己定义赋值重载函数,直接使用默认生成的即可,因为这种类只需要进行浅拷贝 (值拷贝),比如 Date 类;而对于申请了资源的类来说,我们必须自己手动实现赋值重载函数,来完成深拷贝工作,比如 Stack 类。

在这里插入图片描述

如果使用了浅拷贝,造成的问题比拷贝构造函数更多,如上图,不仅会导致 st2._a 指向的空间被析构两次,同时,``st1._a `原本指向的空间还没有被释放,导致内存泄漏。

至于深拷贝的实现也和拷贝构造函数有所不同,除了正常的开辟新空间,拷贝值进去,还要求不能自己给自己赋值。

原因如下图:当我们使用st2 = st2给自己赋值时,operator= 函数首先会将 st2._a 指向的空间释放,然后再为其申请新空间,但是由于 st2 自己给自己赋值,所以用来赋值的数组已经被释放了,里面是随机值,再赋值就会得到错误的结果。

在这里插入图片描述

Stack 类的赋值重载函数的实现:

Stack& operator=(const Stack& st) 
{
    //检查自我赋值
    if (this == &st)
    {
        return *this;
    }

    free(_a);
    _a = (int*)malloc(sizeof(int) * st._capacity);
    if (_a == nullptr)
    {
        perror("malloc fail\n");
        exit(-1);
    }

    memcpy(_a, st._a, sizeof(int) * st._capacity);
    _top = st._top;
    _capacity = st._capacity;

    return *this;
}

说明

  1. 函数采用传引用传参是为了避免在传参的时候调用拷贝构造函数,提高函数运行效率
  2. 同时用 const 关键字进行修饰是为了避免赋值对象st在函数内部被修改
  3. 为了自定义类型支持连续赋值,拷贝构造函数必须有返回值,同时又为了避免在传值返回时调用拷贝构造函数,采用了传引用返回。

另外,和拷贝构造一样,对于成员变量为自定义类型的 MyQueue 类,不用自己定义赋值重载,自动生成的赋值重载函数就够用了。

总结:拷贝构造,析构函数和赋值重载函数,这三者总是同时出现

七、取地址重载

1. const 成员函数

我们将 const 修饰的 “成员函数” 称之为 const 成员函数,const 修饰成员函数实际上是修饰该成员函数隐含的 this 指针,表明在该成员函数中不能对 this 指向的对象中的任何成员变量进行修改;

  • 我们建议不需要改变 *this 的成员函数都用 const 修饰,这是为了能够接收更多类型的 this 指针。
在这里插入图片描述

我们看到,当我们定义了一个只读的 Date 对象 d1 时,我们再去调用 d1 的成员函数 Print 时编译器会报错;原因在于类成员函数的第一个参数默认是 this 指针,而 this 指针的类型是 Date* const,而我们传进去的类型是 const Date*;将一个只读变量赋值给一个可读可写的变量时权限扩大,导致编译器报错;

实际上我们很少在成员函数外面定义只读类型的对象,更多的是在成员函数里面。比如实现运算符重载函数operator–(const Date& d) 时,当运算符重载的两个参数都是类对象时,如果我们不会改变类的内容,我们通常会将函数形参定义为 const Date& 类型,这时在成员函数内部,对象 d 就不能调用一般成员函数,否则就会报错。

所以我们应该把能用 const 进行修饰的成员函数全部用 const 进行修饰,这是为了让常对象也能调用,以Date 类为例:

class Date
{
public:
	//构造
	Date();
	//获取每一个月的天数
	int GetMonthDay(int year, int month) const;
	//获取日期对应天数
	int GetDateDay() const;
	//打印
	void Print() const;

	//运算符重载
	//+=
	Date& operator+=(int day);
	//+
	Date operator+(int day) const;
	//-=
	Date& operator-=(int day);
	//-
	Date operator-(int day) const;
	//前置++
	Date& operator++();
	//后置++
	Date operator++(int);
	//前置--
	Date& operator--();
	//后置--
	Date operator--(int);
	//日期-日期
	int operator-(const Date& d) const;
	//>
	bool operator>(const Date& d) const;
	//==
	bool operator==(const Date& d) const;
	//>=
	bool operator>=(const Date& d) const;
	//<
	bool operator<(const Date& d) const;
	//<=
	bool operator<=(const Date& d) const;
	//!=
	bool operator!=(const Date& d) const;

private:
	int _year;
	int _month;
	int _day;
};

2. 普通对象取地址重载

普通对象取地址重载函数是C++的六个默认成员函数之一,同时它也是运算符重载的一种,它的作用是返回普通对象的地址;

Date* operator&()
{
    return this;
}

3. const 对象取地址重载

const 对象取地址重载函数也是C++的六个默认成员函数之一,它是普通对象取地址重载的重载函数,其作用是返回 const 对象的地址;

const Date* operator&() const
{
    return this;
}

如果我们没有显式定义取地址重载和 const 对象取地址重载函数,那么编译器会自动生成,因为这两个默认成员函数十分固定,所以大多数情况下我们直接使用编译器默认生成的即可,不必自己定义;

八、总结

C++的六个默认成员函数中前面四个默认成员函数非常重要,也非常复杂,需要我们根据具体情况判断是否需要显式定义,大部分情况下,构造函数都需要我们自己定义,其他三个在类中有指针类型的成员变量时同时出现,而最后两个函数通常不需要显示定义,使用编译器默认生成的即可。

C++中的“类和对象” 类的定义,实例化,this指针 阅读详情

相关推荐

C++类和对象(上)

/类体:由成员函数和成员变量组成//一定要注意后面的分号class为定义类的关键字,ClassName为类的名字(自定义),{}中为类的主体,注意类定义结束时后面的分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。类的两种定义方式:1.声明和定义全部放在类体中,需注意: 成员函数如果在类中定义,编译器可能会将其当成内联函数处理。2.类声明放在.h文件中,成员函数的定义放在.cpp文件中。

m0_62183318的博客 807

【c++】cpp类和对象

c++中类和对象基本用法

hutaotaotao的博客 1268

【影像组学入门百问】1#---#3

理论上讲三大主流平台Windows, Linux和MacOS均可进行影像组学研究。根据笔者实际经验,如果内存不足可能导致软件罢工,其余显示、GPU等均非必要。显示:最小分辨率为1024×768(推荐为1280×1024或更好)。Slicer中的许多计算都是多线程的,并且将受益于多核,多CPU配置。计算机需要足够的内存和图形功能将原始数据和处理结果保存在其内存中。如涉及深度学习等方法的研究需根据实际需求配置电脑,无法一概而论。接口设备:推荐使用带滚轮的三键鼠标。内存:超过4GB(推荐8G以上)。

weixin_38594676的博客 1483

Cpp-类和对象

title: 类和对象 date: 2019-03-15 14:05:24 tags: Cpp categories: Cpp 类的引入 万物皆对象。类是一种用户自定义的数据类型,包括表示属性的成员变量和表示行为的成员函数,类是现实世界对象的抽象,对象是类虚拟世界的实例。 C++ 中 struct 中不仅可以有变量,还可以有函数。 类定义结束时后面分号。 成员函数声明和定义可以全部...

ahojcn 的博客 1896

升降机SEW MOVIDRIVE变频器设置

选择PO1 第2,3,9,13 位,点击“SendPA”Start reference,编码器反馈值为0(PI2/3 Actual position=0)提示:传送参考位置前请断开变频器安全24V电源,否则会弹出禁止修改提示框;提示:做这一步时,如果出现电机不能转动,或产生报警不能通过编码器匹配。下载配置的参数,提示:下载参数需要断开变频器的安全24V电源。编码器匹配通过后点击下一步,进入下图画面传送参考位置。1电机不能转动:a可能是由于变频器的安全24V未给。点击2.SEW总线扩展定位,定位块设置。

xdpcxq的专栏 5394

用Omniverse Kit开发第一个USD插件:从环境配置到实战案例(Python 3.7版)

本文详细介绍了如何使用NVIDIA Omniverse Kit和Python 3.7开发第一个USD插件,涵盖从环境配置到实战案例的全过程。通过创建可实时同步材质属性的USD插件,开发者可以快速掌握Omniverse开发框架,提升3D内容创作效率。

x8y9z0的博客 585

cpp.1 C++类和对象(上)

文章目录第一部分 C++入门1.命名空间2.缺省参数3.函数重载4.引用 第一部分 C++入门 1.命名空间 命名空间实际上就是为了防止命名相同会导致很多的冲突,可以使用命名空间对标识符进行本地化,来避免命名的冲突 使用方式: 1.加命名空间名称及作用域限定符std::cout<<"hello world"<<std::endl; 2.使用using将命名空间中成员引入using std::cout; 3.用using namespace 命名空间名称引入using namespac

Pinksatrfish的博客 368

ubuntu安装hodoop详细步骤

进入到Ubuntu系统中打开桌面,点击鼠标右键打开终端,在终端中输入如下命令这样就可以创建一名为hadoop的新用户。给用户输设置密码输入,输入如下命令,设置密码,按提示输入两次然后为hadoop用户增加管理员全新,这样就可以方便部署完成之后输入重启命令,重启一下Ubuntu系统,然后登录到我们创建的hadoop用户上面reboot。

2301_77603488的博客 9198

【C++】类和对象

类的基本思想是数据抽象(data abstraction)和封装(encapsulation)。数据抽象是一种依赖于接口(interface)和实现(implementatino)分离的编程技术。对象是类的实例,类是对象的模板。

jmlangel_的博客 5955

配置思科交换机冗余链路汇聚

本文对交换机端口汇聚配置进行说明

istrangeboy&begin zero的博客 6684

从ADS到SystemVue:当简单链路预算不够用时,我的射频系统级仿真方案升级实录

本文详细介绍了从ADS到SystemVue的射频系统级仿真升级路径,重点分析了基础链路预算在多端口元件和复杂场景下的局限性,并提供了SystemVue在非线性系统验证和跨域协同分析中的优势。通过实际案例展示了如何平滑迁移工具链,提升仿真精度和效率,适用于5G、毫米波雷达等现代射频系统设计。

weixin_34233974的博客 340

CPP:类和对象

cpp类和对象知识点

weixin_54832720的博客 969

UG\NX二次开发 获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态

获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态。

王牌飞行员_里海的博客 1980

【Cpp】类和对象

类的认识,类和对象(一)

石墨博客 1174

R数据分析:广义估计方程式GEE的做法和解释

好久没有更新文章了,因为同学们咨询的问题有点多,另一个原因就是自己实在太懒。。。。 今天继续给大家写广义估计方程式GEE。 In statistics, a generalized estimating equation (GEE) is used to estimate the parameters of a generalized linear model with a possible unknown correlation between outcomes. 上面的英文解释告诉我们,当我们

Codewar的博客 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【C++】类和对象——下

尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其。友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。

L286594的博客 1361

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【C++】类和对象核心总结

类的引入+定义(struct ==> class),类的访问限定符+封装+作用域,类的实例化(类 类型创建对象的过程)+计算类的大小(考虑内存对齐),隐藏的this指针,类的六个默认成员函数,初始化列表(声明远远不够,还得定义对象),explict关键字,static成员,友元,内部类,匿名对象,编译器优化

小羊study_sheep的博客 5593

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C++实验四——类和对象(2)

实验报告题目1题目2 【实验名称】 实验四 类和对象(2) 【实验内容】 题目1 课本习题4.10 设计一个用于人事管理的“人员”类。由于考虑到通用性,这里只抽象出所有类型人员都具有的属性:编号、性别、出生日期、身份证号等。其中“出生日期”声明为一个“日期”类内嵌子对象。用成员函数实现对人员信息的录人和显示。要求包括:构造函数和析构函数、复制构造函数、内联成员函数、带默认形参值的成员函数、类的组合。 源代码: Date.h /*出生日期类声明*/ #ifndef _Date_H_ #

Onlyone_1314的博客 2336

【C++指南】一文总结C++类和对象【下】

本章节主要讲初始化列表、类型转换、静态成员变量和函数、友元、内部类、匿名对象及编译器优化的各种情况。

egoist2023的博客 3493

c++学习 类和对象上

【代码】c++学习 类和对象上。

qq_50934329的博客 198

【C++】类和对象【上】

本期博客带你了解C++中类和对象相关知识。

2401_86785052的博客 1042

【C++】类和对象(1)

C++类和对象,内存对齐,this指针,

Xie_sheng的博客 1791

cpp中的类和对象

类和对象的区别: 类(class):概念产物,是设计产物(相对于图纸),没有开辟空间 对象(object):是由类实例化出来的代码和数据的集合 类的实例化就成为了对象 我们操纵的是对象,不是类 封装特性:对外是不可访问的 this指针 编译过程: 第一步:识别类里面的属性成员(变量) 第二步:识别方法,只识别方法的声明 第三步:改写 ...

qq_44423388的博客 951

C++类和对象

声明和定义放到类体中public:public:char*_name;char*_sex;int _age;声明放.h文件中,类的定义放.cpp文件中。

mzk_c的博客 1822

C++ ——类和对象

C++ ——类和对象C++ ——类和对象C++ ——类和对象C++ ——类和对象C++ ——类和对象C++ ——类和对象

weixin_49376454的博客 1230
上一篇: C++ 类和对象(上)
岸边露伴'
博客等级 码龄3年 2粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值