专栏首页cwl_JavaC++-面向对象(八)

C++-面向对象(八)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/weixin_42528266/article/details/102756279

引用类型成员
  • 引用类型成员变量必须初始化(不考虑static情况)
    • 在声明的时候直接初始化
    • 通过初始化列表初始化
拷贝构造函数(Copy Constructor)
  • 拷贝构造函数是构造函数的一种
  • 当利用已存在的对象创建一个新对象时(类似于拷贝),就会调用新对象的拷贝构造函数进行初始化
  • 拷贝构造函数的格式是固定的,接收一个const引用作为参数
#include <iostream>
using namespace std;

class Car {
	int m_price;
	int m_length;

public:
	Car(int price = 0, int length = 0) :m_price(price), m_length(length) {
		cout << "Car(int price = 0, int length = 0)" << endl;
	}

	// 拷贝构造函数(格式是固定的)
	Car(const Car &car) :m_price(car.m_price), m_length(car.m_length) {
		// this->m_price = car.m_price;
		// this->m_length = car.m_length;

		cout << "Car(const Car &car)" << endl;
	}

	void display() {
		cout << "price=" << this->m_price << ", length=" << this->m_length  << endl;
	}
};

class Person {
	int m_age;
public:
	Person(int age = 0) :m_age(age) { }
	Person(const Person &person) :m_age(person.m_age) { }
};

class Student : public Person {
	int m_score;
public:
	Student(int age = 0, int score = 0) :Person(age), m_score(score) { }
	Student(const Student &student) :Person(student), m_score(student.m_score) { }
};

int main() {
	//Car car1;

	//Car car2(100, 5);

	//// 利用car2对象创建了car3对象,会调用car3对象的拷贝构造函数进行初始化
	//Car car3(car2);
	//car3.display();

	//cout << "&car2 = " << &car2 << endl;
	//cout << "&car3 = " << &car3 << endl;

	// Car car2(100, 5);
	// Car car3 = car2; // 等价于Car car3(car2)

	//Car car2(100, 5);
	//Car car3;
	// 这里是赋值操作,直接将car2的8个字节数据拷贝给car3的8个字节
	// 但这并不是创建新对象,所以不会调用拷贝构造函数
	//car3 = car2;
	// car3.m_price = car2.m_price;
	// car3.m_length = car2.m_length;

	getchar();
	return 0;
}
拷贝构造函数
  • car2、car3都是通过拷贝构造函数初始化的,car、car4是通过非拷贝构造函数初始化
  • car4 = car3是一个赋值操作(默认是浅复制),并不会调用拷贝构造函数
浅拷贝、深拷贝
  • 编译器默认的提供的拷贝是浅拷贝(shallow copy) 将一个对象中所有成员变量的值拷贝到另一个对象
    • 如果某个成员变量是个指针,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间
    • 可能会导致堆空间多次free的问题
  • 如果需要实现深拷贝(deep copy),就需要自定义拷贝构造函数
    • 将指针类型的成员变量所指向的内存空间,拷贝到新的内存空间
#include <iostream>
using namespace std;

// 浅拷贝(shallow copy):指针类型仅仅是拷贝地址值
// 深拷贝(deep copy):拷贝内容到新申请的内存空间

class Car {
	int m_price;
	char *m_name;

public:
	Car(int price = 0, const char *name = NULL) :m_price(price) { 
		if (name == NULL) return;

		// 申请堆空间存储字符串内容
		this->m_name = new char[strlen(name) + 1]{};
		// 拷贝字符串内容到堆空间(string copy)
		strcpy(this->m_name, name);

		cout << "Car(int, const char *)" << endl;
	}

	Car(const Car &car) :m_price(car.m_price) {
		if (car.m_name == NULL) return;

		// 申请堆空间存储字符串内容
		this->m_name = new char[strlen(car.m_name) + 1]{};
		// 拷贝字符串内容到堆空间(string copy)
		strcpy(this->m_name, car.m_name);

		cout << "Car(const Car &car)" << endl;
	}

	~Car() {
		if (this->m_name == NULL) return;

		delete[] this->m_name;
		this->m_name = NULL;

		cout << "~Car()" << endl;
	}

	void display() {
		cout << "price is " << this->m_price << ", name is " << this->m_name << endl;
	} 
};


int main() {
	/*char name[] = { 'b', 'm', 'w', '\0' };
	Car *car = new Car(100, name);
	car->display();
	delete car;*/


	Car car1(100, "bmw");

	// 将car1的内存空间(8个字节)覆盖car2的内存空间(8个字节)
	Car car2 = car1;

	cout << endl;


	// Car car(100, "bmw");


	//char name[] = { 'b', 'm', 'w', '\0' };
	//const char *name2 = "bmw";

	//cout << name2 << endl;

	//// string length
	//cout << strlen(name) << endl;

	getchar();
	return 0;
}
对象型参数和返回值
  • 使用对象类型作为函数的参数或者返回值,可能会产生一些不必要的中间对象
#include <iostream>
using namespace std;

class Car {
	int m_price;
public:
	Car(int price = 0) :m_price(price) { 
		cout << "Car(int) - " << this << " - " << this->m_price << endl;
	}

	Car(const Car &car) :m_price(car.m_price) {
		cout << "Car(const Car &) - " << this << " - " << this->m_price << endl;
	}
};
 
//void test1(Car &car) {
//
//}
void test1(Car car) {

}

Car test2() {
	Car car(10);
	return car;
}

int main() {
	// Car car1(10);
	// test1(car1);

	Car car2 = test2();

	// Car car3;
	// car3 = test2();


	getchar();
	return 0;
}
匿名对象(临时对象)
  • 匿名对象:没有变量名、没有被指针指向的对象,用完后马上调用析构
#include <iostream>
using namespace std;

class Person {
public:
	Person() {
		cout << "Person() - " << this << endl;
	}
	Person(const Person &person) {
		cout << "Person(const Person &person) - " << this << endl;
	}
	~Person() {
		cout << "~Person() - " << this << endl;
	}
	void display() {
		cout << "display()"  << endl;
	}
};

void test1(Person person) {

}

Person test2() {
	// Person person;
	return Person();
}

int main() {
	Person person1;
	person1 = test2();

	// Person person;

	// Person *p = new Person();

	// cout << 1 << endl;
	
	// Person().display();

	// cout << 2 << endl;

	// Person person;
	// test1(person);

	// test1(Person());

	// Person person = Person();

	getchar();
	return 0;
}
隐式构造
  • C++中存在隐式构造的现象:某些情况下,会隐式调用单参数的构造函数
  • 可以通过关键字explicit禁止掉隐式构造
#include <iostream>
using namespace std;

class Person {
	int m_age;
public:
	Person()  {
		cout << "Person() - " << this << endl;
	}
	explicit Person(int age) :m_age(age) {
		cout << "Person(int) - " << this << endl;
	}
	Person(const Person &person) {
		cout << "Person(const Person &person) - " << this << endl;
	}
	~Person() {
		cout << "~Person() - " << this << endl;
	}
	void display() {
		cout << "display() - age is " << this->m_age << endl;
	}
};

void test1(Person person) {

}

Person test2() {
	return 30;
}

int main() {

	// test1(40);

	// Person person = test2();
	// Person person(10);
	// person = test2();

	Person person = 10;

	// Person person(10);
	person = 20;
	// person.display();
		
	getchar();
	return 0;
}
编译器自动生成的构造函数
  • C++的编译器在某些特定的情况下,会给类自动生成无参的构造函数,比如
    • 成员变量在声明的同时进行了初始化
    • 有定义虚函数
    • 虚继承了其他类
    • 包含了对象类型的成员,且这个成员有构造函数(编译器生成或自定义)
    • 父类有构造函数(编译器生成或自定义)
  • 总结
    • 对象创建后,需要做一些额外操作时(比如内存操作、函数调用),编译器一般都会为其自动生成无参的构造函数
#include <iostream>
using namespace std;

/*
编译器会为每个类生成一个默认的无参的构造函数
*/

class Person {
public:
	int m_age = 0;
};

class Student : public Person {

};

int main() {
	Student student;

	getchar();
	return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++-面向对象(二)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    cwl_java
  • C++-面向对象(九)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    cwl_java
  • 快速学习-Linux文档的查看指令

    作用:查看一个文件的末n行 语法:#tail -n 文件的路径 说明:-n可以不写,不写,默认表示10行。 案例:使用tail指令查看root/insta...

    cwl_java
  • Java中JDBC工具类封装

    mcxfate
  • Sass 基础(四)

    当你想设置属性值的时候你可以使用字符串插入进来,另一个使用的用法是构建一个选择器。       @mixin generate-sizes($class,$s...

    用户1197315
  • Vue项目图片剪切上传——vue-cropper的使用

    最近自己在研究vue,然后做了一个小型的后台管理系统用来练手,开发过程中,想到了剪切图片上传用户头像的需求。上网百度了一番,发现好多用的都是vue-croppe...

    用户1174387
  • 独家 | 一文带你读懂特征工程!

    本文描述了一个典型的基于跨行业标准流程的标准机器学习管道,作为数据挖掘行业的标准过程模型。

    数据派THU
  • 迟来的面经-双非二本上岸WX支付

    想起来春招是真的艰难险阻。楼主三月份就开始投各大公司,360三面完成后加入offer池就无消息。

    牛客网
  • 数据分析告诉你富人为什么有钱?

    用户1756920
  • Squid 代理服务器详解

    Squid是一个支持HTTP,HTTPS,FTP等服务的Web缓存代理软件,它可以通过缓存页面来提高服务器的相应速度并降低带宽占用。并且,Squid还具有强大的...

    魏豪

扫码关注云+社区

领取腾讯云代金券