C++——类的真正形态、构造函数的调用

1.class和struct的区别:用struct定义类时,所有成员的默认访问级别为public;用class定义类时,所有成员的默认访问级别为private

2.类定义中成员变量i和j的初始值

复制代码
#include <stdio.h>
class Test {
private:
	int i;
	int j;
public:
	int getI() {
		return i;
	}
	int getJ() {
		return j;
	}
};
Test gt;
int main() {
	printf("gt.i=%d\n", gt.getI());
	printf("gt.j=%d\n", gt.getJ());
	Test t1;
	printf("t1.i=%d\n", t1.getI());
	printf("t1.j=%d\n", t1.getJ());
	Test* pt = new Test;
	printf("pt.i=%d\n", pt->getI());
	printf("pt.j=%d\n", pt->getJ());
    delete pt;
	return 0;
}

结果:

gt存放在全局区,静态存储区创建的成员,成员变量初始值为0;t1在栈区,初始值为随机值;pt在堆空间,初始值是随机值

2.构造函数的自动调用

复制代码
#include <stdio.h>
class Test {
public:
	Test(){
		printf("Test()\n");
	}
	Test(int v){
		printf("Test(int v)\n");
	}
};
int main() {
	Test t; //Test()
    //初始化方式:
	Test t1(1); //Test(int v)
	Test t2 = 1; //Test(int v)
    Test t3=Test(100); //Test(int v)
	return 0;
}

一些特殊情况下需要手工调用构造函数

定义一个数组,如果默认调用时,均调用无参构造函数

复制代码
#include <stdio.h>
class Test {
private:
	int m_value;
public:
	Test(){
		printf("Test()\n");
		m_value = 0;
	}
	Test(int v){
		printf("Test(int v)\n");
		m_value = v;
	}
	int getValue() {
		return m_value;
	}
};
int main() {
	Test ta[3];
	for (int i = 0; i < 3; i++) {
		printf("ta[%d].getValue()=%d\n", i, ta[i].getValue());
	}
	return 0;
}

结果:

手动调用后:

复制代码
#include <stdio.h>
class Test {
private:
	int m_value;
public:
	Test(){
		printf("Test()\n");
		m_value = 0;
	}
	Test(int v){
		printf("Test(int v)\n");
		m_value = v;
	}
	int getValue() {
		return m_value;
	}
};
int main() {
	Test ta[3] = {Test(),Test(1),Test(2)};
	for (int i = 0; i < 3; i++) {
		printf("ta[%d].getValue()=%d\n", i, ta[i].getValue());
	}
	return 0;
}

结果:

3.示例:开发一个数组类解决原生数组的安全性问题:提供函数获取数组长度、获取数组元素、设置数组元素

intArray.h

复制代码
#pragma once
class IntArray {
private:
	int m_length;
	int* m_pointer;

public:
	IntArray(int len);
	IntArray(const IntArray& obj);
	int length();
	bool get(int index, int& value); //index是数组下标
	bool set(int index, int value);
	void free();
};

intArray.cpp

复制代码
#include "intArray.h"
IntArray::IntArray(int len) {
	m_pointer = new int[len];
	for (int i = 0; i < len; i++) {
		m_pointer[i] = 0;
	}
	m_length = len;
}
IntArray::IntArray(const IntArray& obj) {
	m_length = obj.m_length;
	m_pointer = new int[obj.m_length];
	for (int i = 0; i < obj.m_length; i++) {
		m_pointer[i] = obj.m_pointer[i];
	}
}
int IntArray::length() {
	return m_length;
}
bool IntArray::get(int index, int& value) {
	bool ret = (0 <= index) && (index < length());
	if (ret) {
		value = m_pointer[index];
	}
	return ret;
}
bool IntArray::set(int index, int value) {
	bool ret = (0 <= index) && (index < length());
	if (ret) {
		m_pointer[index] = value;
	}
	return ret;
}
void IntArray::free() {
	delete[]m_pointer;
}

main.cpp

复制代码
#include <stdio.h>
#include "intArray.h"
int main() {
	
	IntArray a(5); //调用 IntArray 的构造函数
	for (int i = 0; i < a.length(); i++) {
		a.set(i, i + 1);
	}
	for (int i = 0; i < a.length(); i++) {
		int value = 0;
		if (a.get(i, value)) {
			printf("a[%d]=%d\n", i, value);
		}
	}
    IntArray b=a;
    for (int i = 0; i < b.length(); i++) {
		int value = 0;
		if (b.get(i, value)) {
			printf("b[%d]=%d\n", i, value);
		}
	}
	a.free();
    b.free();
    return 0;
}

4.两个特殊的构造函数------无参构造函数、拷贝构造函数

无参构造:当类中没有定义构造函数时,编译器就默认提供一个无参构造函数,并且函数体为空

拷贝构造:当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,简单进行成员变量的值复制

若定义带参构造函数后,编译器不会自动生成 默认无参构造函数,若自定义拷贝构造函数后,编译器不会自动生成默认无参构造函数,若只定义了带参构造函数时,编译器仍然会自动生成默认的拷贝构造函数

5.深拷贝与浅拷贝

复制代码
#include <stdio.h>
class Test {
private:
	int i;
	int j;
	int* p;
public:
	int getI() {
		return i;
	}
	int getJ() {
		return j;
	}
	int* getP() {
		return p;
	}
	Test(const Test& t) {
		i = t.i;
		j = t.j;
	}
	Test(int v) {
		i = 1;
		j = 2;
		p = new int;
		*p = v;
	}
	void free() {
		delete p;
	}
};

int main() {
	Test t1(3);
	Test t2 = t1;
	printf("t1.i=%d,t1.j=%d,t1.p=%p\n", t1.getI(), t1.getJ(), t1.getP());
	printf("t2.i=%d,t2.j=%d,t2.p=%p\n", t2.getI(), t2.getJ(), t2.getP());
	t1.free();
	t2.free(); //报错,因为t1和t2的指针指向同一块内存空间,t1释放之后,t2就不能再释放了
	return 0;
}

为了防止这种错误,t2应该也要指向一个新的堆空间,即深拷贝

复制代码
#include <stdio.h>
class Test {
private:
	int i;
	int j;
	int* p;
public:
	int getI() {
		return i;
	}
	int getJ() {
		return j;
	}
	int* getP() {
		return p;
	}
	Test(const Test& t) {
		i = t.i;
		j = t.j;
		p = new int;
		*p = *t.p;
	}
	Test(int v) {
		i = 1;
		j = 2;
		p = new int;
		*p = v;
	}
	void free() {
		delete p;
	}
};

int main() {
	Test t1(3);
	Test t2(t1);
    //或者也可以写成Test t2=t1
	printf("t1.i=%d,t1.j=%d,t1.p=%p\n", t1.getI(), t1.getJ(), t1.getP());
	printf("t2.i=%d,t2.j=%d,t2.p=%p\n", t2.getI(), t2.getJ(), t2.getP());
	t1.free();
	t2.free(); //报错,因为t1和t2的指针指向同一块内存空间,t1释放之后,t2就不能再释放了
	return 0;
}
相关推荐
fqbqrr8 小时前
2607C++,使用微软detours勾挂工具
c++
人邮异步社区8 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大8 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai8 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜9 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa9 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行9 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
噢,我明白了10 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
mabing99311 小时前
Qt 生成条纹图
开发语言·qt
蓝悦无人机11 小时前
C++基础 — 函数总结
开发语言·c++