一、结构函数简介
结构函数(构造函数)是一个特殊的成员函数,主要作用是在创建对象时对其进行初始化操作。在C++中,每个类可以拥有一个或多个结构函数,且结构函数名称与类名称相同,没有返回值类型,可以有参数或不带参数。当对象被创建时,结构函数会自动调用,完成对象的初始化工作。
class Person {
public:
Person() {
name = "Unknown";
age = 0;
}
Person(string n, int a) {
name = n;
age = a;
}
private:
string name;
int age;
};
上述代码定义了一个Person类,并定义了两个结构函数。第一个结构函数不带参数,用于默认初始化name为“Unknown”、age为0;第二个结构函数带有两个参数,用于指定类成员的值。在创建Person对象时,就会自动调用结构函数进行初始化。
二、结构函数分类
C++结构函数可分为默认结构函数、拷贝结构函数、移动结构函数和转换结构函数等几种类型。 1. 默认结构函数 在类中没有定义结构函数时,编译器会自动生成一个默认结构函数。如果不需要自定义结构函数,可以直接使用默认结构函数。
class Person {
public:
string name;
int age;
};
Person p; // 调用默认结构函数初始化
2. 拷贝结构函数 拷贝结构函数用于在对象之间进行赋值或参数传递时调用。拷贝结构函数有两种形式: a) 浅拷贝结构函数:成员变量逐一进行复制,指针成员变量仍指向同一内存地址。
class Person {
public:
Person(int a, char* n) {
age = a;
name = new char[strlen(n)+1];
strcpy(name, n);
}
Person(const Person &p) { // 拷贝结构函数
age = p.age;
name = p.name; // 浅拷贝,指针成员变量仍指向同一地址
}
~Person() {
delete[] name; // delete释放new申请的内存
}
private:
char* name;
int age;
};
Person p1(18, "Tom");
Person p2 = p1; // 调用拷贝结构函数
在上述代码中,用new动态申请了一段内存来存储类成员name的值。在拷贝结构函数中,进行了浅拷贝,即将指针成员变量直接复制,不重新分配内存。这样会导致p1和p2的name指针变量都指向同一块内存地址,造成内存重复释放问题。 b) 深拷贝结构函数:对指针成员变量进行新的内存分配,复制值到新的内存空间中。
class Person {
public:
Person(int a, char* n) {
age = a;
name = new char[strlen(n)+1];
strcpy(name, n);
}
Person(const Person &p) { // 拷贝结构函数
age = p.age;
name = new char[strlen(p.name)+1]; // 深拷贝,重新分配内存
strcpy(name, p.name);
}
~Person() {
delete[] name; // delete释放new申请的内存
}
private:
char* name;
int age;
};
Person p1(18, "Tom");
Person p2 = p1; // 调用拷贝结构函数
在上述代码中,在拷贝结构函数中重新分配了一段新的内存空间,将原指针成员变量的值复制到新的空间中,避免了内存重复释放问题。 3. 移动结构函数 移动结构函数用于在对象之间进行赋值操作时调用,且源对象的资源不需要保留。在移动结构函数中,首先进行资源的交换,然后将源对象的资源清空。
class Person {
public:
Person(int a, string n) {
age = a;
name = n;
}
Person(Person &&p) { // 移动结构函数
age = p.age;
name = p.name;
p.name = ""; // 清空源对象的资源
}
private:
string name;
int age;
};
Person p1(18, "Tom");
Person p2 = move(p1); // 调用移动结构函数
在上述代码中,使用move()函数调用了移动结构函数,进行资源的移动和清空。 4. 转换结构函数 转换函数(类型转换函数)用于将一个类类型对象转换为另一个类型的对象,可以使用显示或隐式类型转换。转换结构函数没有返回值类型,名称和类名称相同,可以有或没有参数。
三、结构函数的特殊条件
1. 虚拟结构函数 虚拟结构函数(虚构造函数)是一个声明为虚拟的结构函数。在一个继承关系的类中,当通过指针或引用调用一个虚拟结构函数时,会自动调用最适当的版本,即最终派生类实现的版本。使用虚拟结构函数的主要目的是实现运行时多态。
class Person {
public:
virtual ~Person() {} // 定义虚拟结构函数
};
class Student : public Person {
public:
~Student() {}
};
Person* p = new Student(); // 使用指针调用虚拟结构函数
delete p; // 调用最终派生类的析构函数
在上述代码中,定义了一个虚拟结构函数,在派生类中重新定义了析构函数。在创建Student对象时,使用指针访问虚拟结构函数,当释放内存时,自动调用最终派生类Student的析构函数。 2. 纯虚拟结构函数 纯虚拟结构函数(纯虚构造函数)是一个没有实现的虚拟结构函数,其目的是在基类中定义一个接口,强制派生类必须实现该接口。在定义纯虚拟结构函数时,需要在结构函数后面加上“= 0”,表示没有实现该函数。不能直接创建一个纯虚拟结构函数的对象。
class Person {
public:
virtual void show() = 0;
};
class Student : public Person {
public:
void show() {
cout << "I am a student." << endl;
}
};
Person* p = new Student();
p->show();
delete p;
在上述代码中,定义了一个纯虚拟结构函数show(),在派生类Student中实现了该函数。在创建Student对象时,使用指针调用show()函数。
四、结构函数的应用
1. 对象间的依赖关系 结构函数可以用于在创建对象时,对对象之间的依赖关系进行设置。
class Person {
public:
Person() {
t = new Time(0, 0, 0);
}
void setTime(int h, int m, int s) {
t->setTime(h, m, s);
}
private:
Time* t;
};
class Time {
public:
Time(int h, int m, int s) {
hour = h;
minute = m;
second = s;
}
void setTime(int h, int m, int s) {
hour = h;
minute = m;
second = s;
}
private:
int hour;
int minute;
int second;
};
在上述代码中,创建了一个Person类和一个Time类,在Person类中创建了一个Time对象的指针t,并在结构函数中对其进行初始化。在Person类中还定义了一个设置时间的函数,通过t指针间接访问Time对象,并设置时间。这样就形成了一个Person对象和一个Time对象之间的依赖关系。 2. 继承的应用 结构函数的重载和继承可用于强制派生类对基类成员进行初始化或重新定义。
class Base {
public:
Base(int a) {
num = a;
}
virtual void show() {
cout << "Base: " << num << endl;
}
private:
int num;
};
class Son : public Base {
public:
Son(int a, int b) : Base(a) { // 调用基类结构函数进行初始化
age = b;
}
void show() {
cout << "Son: " << age << endl;
}
private:
int age;
};
在上述代码中,定义了一个基类Base和一个派生类Son。在派生类结构函数中通过冒号(:)调用基类结构函数对基类成员num进行初始化,以保证基类成员的正确性。在派生类中重新定义了show()函数,对基类函数进行了覆盖,实现了多态效果。
五、结构函数的注意事项
1. 不要滥用结构函数 结构函数虽然可以提高代码的可读性和可靠性,但也需要谨慎使用。滥用结构函数会造成代码的复杂性,对程序性能产生影响。 2. 注意结构函数的访问权限 结构函数可以是公有、私有或受保护的,需要根据实际应用场景进行选择。 3. 不允许自动转换 结构函数不能有返回值类型,也不允许自动类型转换,只能通过显示类型转换完成。 4. 继承和多态 结构函数的继承和多态是C++面向对象编程的重要特性,可以实现代码的可扩展性和复用性。
六、总结
结构函数是一种特殊的成员函数,用于在创建对象时进行初始化操作。C++结构函数可分为默认结构函数、拷贝结构函数、移动结构函数和转换结构函数等几种类型。在使用结构函数时,需要注意虚拟结构函数、纯虚拟结构函数的定义和继承、多态等特性。通过合理的应用结构函数,可以提高代码的可读性和可靠性,增强程序的稳定性和可扩展性。