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;
}
相关推荐
lsx2024061 小时前
HTML 媒体(Media)详解
开发语言
PieroPc1 小时前
用python 写的 Gitee 数据备份工具
开发语言·python·gitee
csbysj20201 小时前
Bootstrap 多媒体对象
开发语言
桂花很香,旭很美2 小时前
[7天实战入门Go语言后端] Day 7:综合实战——小型 REST API 与优雅关闭
开发语言·后端·golang
CHANG_THE_WORLD2 小时前
C/C++字符串定义的五种写法 和 C/C++字符串隐藏技术深度剖析
c++
sycmancia2 小时前
C++——初始化列表的使用
开发语言·c++
番茄去哪了2 小时前
在Java中操作Redis
java·开发语言·数据库·redis
马克Markorg2 小时前
使用rust实现的高性能api测试工具
开发语言·测试工具·rust·postman
白太岁2 小时前
Redis:(3) Lua 与 Redis、基于连接池的 Facade 模式封装
数据库·c++·redis·lua·外观模式