0%

C++小知识点总结2

深拷贝和浅拷贝的简单区别

拷贝构造函数是一种特殊的构造函数,在创建对象时,它是使用同一类中之前创建过的对象来初始化新创建的对象

strcpy是深拷贝,“=”是浅拷贝

  1. 使用strcpy时会有两个字符串;而使用“=”只有一个字符串

  2. strcpy是将字符串拷贝到指定地址

1
2
3
4
5
6
7
char * str1 = "字符串";//在栈区声明一个  char* 变量str1 并初始化它,让他指向data区的 “字符串”
//char * str1 ="字符串2";//erro 多次初始化

char * str2 = str1;//在栈区声明一个char* 变量str2;并给将str1中的值复制给它.
//str1中存储的就是堆区“字符串”的地址;这一个过程不是初始化,
//所以后面str2还可执行str2 = "字符串3"这一操作
str2 = "字符串3"

我们在编写程序的过程中,如果不主动编写拷贝构造函数和赋值函数,编译器将会调用默认的函数,如果类中含有指针变量,那么如果使用的默认的函数就会有错误,下面首先我们先进行简单的介绍,之后再用具体的例子来加以说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <cstring>
#pragma warning(disable : 4996)
using namespace std;

class Person {

public:
char* name; // 姓名
int age; // 年龄

Person(const char* name, int age) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->age = age;
}

// write your code here......
Person(const Person &a)//为了防止再创建一个Person类(形参)占用空间,我们这里传引用。
//并且为了避免在函数中修改对象的值,我们用const修饰对象,即常引用,但是若要调用函数,则去掉const
{
age = a.age;
name = new char[strlen(a.name)];//开辟新空间
strcpy(name,a.name);//用strcpy主要是让两个对象的空间不一样,防止析构函数二次删除
//空间导致程序崩溃(堆区内存重复释放)
}

void showPerson() {
cout << name << " " << age << endl;
}

~Person() {
if (name != nullptr) {
delete[] name;
name = nullptr;
}
}

};

int main() {

char name[100] = { 0 };
int age;

cin >> name;
cin >> age;

Person p1(name, age);
Person p2 = p1;

p2.showPerson();

return 0;
}

下面再用两个图来说明其区别

strcpy操作方法

img

“=”操作方法

img

数组类的拷贝函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
#include<cstring>
using namespace std;
class Array{
private:
int n;//数组大小
int *a;//数组
public:
Array(){
cin>>n;
a=new int [n];
for (int i=0;i<n;i++) cin>>a[i];
}
~Array(){
delete []a;
}
int getlen(){
return n;
}
int get(int i){
return a[i];
}
// write your code here......
Array(const Array &c)//若要调用函数,则取消const
{
n=c.n;//也可n=c.getlen();
a=new int[n];
for(int i=0;i<n;i++)
{
a[i]=c.a[i];//也可c.get(i);
}
}
void show(){
for (int i=0;i<n;i++) cout<<a[i]<<' ';
}
};
int main(){
Array a;
Array b=a;
b.show();
return 0;
}

C++函数后面加”:”

1
Sub(int x, int y, int z):Base(x,y)

上述语句中单冒号“:”的作用时表示后面是初始化列表,一般有三种使用场景

1.对父类进行初始化

调用格式为子类构造函数 : 父类构造函数,如下,其中QMainWindow是MyWindow的父类:

1
MyWindow::MyWindow(QWidget* parent , Qt::WindowFlags flag) : QMainWindow(parent,flag)

2.对类成员进行初始化

1
2
3
4
5
6
7
8
9
A( int aa, int bb ):a(aa),b(bb)
{
}
//相当于
A( int aa, int bb )
{
a=aa;
b=bb;
}

3.对类的const成员变量进行初始化

由于const成员变量的值无法在构造函数内部初始化,因此只能在变量定义时赋值或使用初始化列表赋值。

对于2、3中的应用场景,有以下两点说明:

1、构造函数列表初始化执行顺序与成员变量在类中声明顺序相同,与初始化列表中语句书写先后无关。

2、相对于在构造函数中赋值,初始化列表执行效率更高。

下面上一道例题让大家品一品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>
using namespace std;
class rectangle{
private:
int length,width;
public:
rectangle(int x,int y){
length=x;
width=y;
}
void set(int x,int y){
length=x;
width=y;
}
int area(){
return length*width;
}
};
class cuboid:public rectangle{
private:
int height;
public:
/* write your code here...继承会把私有变量也继承,只不过不能直接访问,但是可以通过
继承的函数间接访问啊*/
cuboid(int x,int y,int z):rectangle(x,y)
{
height=z;
}
int getvolume()
{
return area()*height;
}
};
int main(){
int x,y,z;
cin>>x>>y>>z;
cuboid a(x,y,z);
cout<<a.getvolume();
return 0;
}

for循环中加:

正常我们想要输出一个数组的全部元素时,需要采用以下的方法:

1
2
3
4
5
6
7
//随机定义的数组
int arr[10] = { 54, 23, 78, 9, 15, 18, 63, 33, 87, 66 };

for (int i = 0; i < 10; i++)
{
cout << arr[i] << " "; //输出:54 23 78 9 15 18 63 33 87 66
}

在C++11中,我们可以在for循环填加冒号 : 来简化这一过程:

1
2
3
4
5
6
7
8
9
10
11
//随机定义的数组
int arr[10] = { 54, 23, 78, 9, 15, 18, 63, 33, 87, 66 };

for (auto a : arr) //这里arr是数组名
{
cout << a << " "; //输出:54 23 78 9 15 18 63 33 87 66
}
for (auto &a : arr) //利用 引用 方法可以改变数组中的数值
{
cout << a << " "; //输出:54 23 78 9 15 18 63 33 87 66
}

需要注意的是:

如果传入的迭代参数类型为非引用时,做的是值拷贝,因此修改数据是无效的