struct and class
struct
struct 和 class 都是由各种数据组成的集合(也叫做类),这些数据可以是整数,浮点数,字符,也可以是函数。在代码中,我们首先定义集合的名字,包含的数据类别。之后可以命名需用的集合,在主函数或者一些函数中对这些集合调用。
先对 struct 做一个示例:
#include<iostream>
using namespace std;
//定义一种结构体的名字,之后你可以把node理解为和int,string同样效果的东西
struct node{
int x,y;//定义node中我要包含的数据
};
int main()
{
node a;//定义一个变量a,他的数据类型就是你的node
//然后你就可以对a里面的数据调用
a.x=1;a.y=2;
cout<<a.x<<endl;
cout<<a.y<<endl;
return 0;
}
struct 里面也可以进行函数的定义。并可以直接调用自身所包含的数据并作出修改。(调用自身的含义,是指不需要使用 \(a.x\) 而可以直接写 \(x\))。
#include<iostream>
using namespace std;
struct node{
int x,y;
void add(){
x=x+y;
}
};
int main()
{
node a;
a.x=1;a.y=2;
cout<<a.x<<endl;
cout<<a.y<<endl;
a.add();
cout<<a.x<<endl;
return 0;
}
数据权限
class 和 struct 最大的区别,在于数据权限的默认值,数据权限分为三种:public, private, protected。
public: main 函数和子类 class 可以调用。
private: main 函数和子类 class 都不可以调用。
protected: main 函数不可以,子类 class 可以调用。
我们用代码及结果来理解权限的含义
class A{
public:
int x;
protected:
int y;
private:
int z;
}
int main()
{
A a;
cout<<a.x;//1
cout<<a.y;//2
cout<<a.z;//3
}
这样写只有语句1可以正常输出,语句2,3都会使你编译错误。
子类的写法:
class B: <type> A
这样的写法表示 B 继承了 A 里面所有权限为 public 和 protected的数据.
继承后的权限则由你所写的 type 决定,我们考虑三种权限限制程度递进为:public,protected,private。type是你希望改变的权限,各数据会在原本的权限和 type 间进行比较,选择限制程度更深的那个。具体可以将type分为两类:
public: A 中 public 和 protected 权限不变的继承给 B。
private/protected: A 中 public 和 protected 继承给 B 后权限均更改为 type。
class A
{
protected:
int x;
};
class B : public A{
public:
void print(){
cout<<x;
}
};
int main()
{
B b;
b.print();
}
这里就是 \(x\) 在 A 中为 protected,你用 public 去继承,它的权限保持不变,你就必须用函数去输出他,而不是直接 \(cout<<b.x\)。
总结下需要注意的两点是:
1.子类不可调用基类的 private。
2.子类调用数据后,权限是二者比较,取限制更深。
这里就可以提到 struct 和 class 的区别:如果不定义数据权限,struct 里面的值默认为 public,而 class 里面的值默认为 private。这就是为什么我们不用在 struct 里面定义数据权限,他就可以在主函数里面被调用,直接做各种计算。
所以对于 class,我们一般会定义权限为 public 的函数,来对 private 的数据进行读入,计算,输出。如:
class A{
public:
void print(){
cout<<x;
}
private:
int x=2;
};
int main()
{
A a;
a.print();
}
构造函数(Constructors)
对类的数据成员进行初始化,对各个数据赋予初始值。
为什么要有这个函数?对于普通的局部变量来说,如果不赋予初值,那么他的初始值是随机的,所以初始化就非常重要,例如一个人的年龄不可能是负数,在不初始化的情况下,可能出现一些预估外的错误。
构造函数的形式为:
class A{
public:
A(int a){
x=a;
}
void print(){
cout<<x;
}
private:
int x;
};
int main()
{
A a(2);
a.print();
}
一个 class 可以写多个构造函数,区分它们的方法是 \(A()\) 括号中的内容,我们去定义class变量时,如上述代码中的 \(a(2)\),系统会根据括号里的数据类型去匹配你写的构造函数,然后执行。
代码示例
class info{
public:
info(){//对应下面的a
name="unknown";
age=0;
}
info(string s){//对应下面的b
name=s;
age=0;
}
info(int a){//对应下面的c
name="unknown";
age=a;
}
info(string s,int a){//对应下面的d
name=s;
age=a;
}
void getname(string s){
name=s;
}
void printname(){
cout<<name<<endl;
}
void getage(int b){
age=b;
}
void printage(){
cout<<age<<endl;
}
private:
string name;
int age;
};
int main()
{
info a,b("Niu"),c(18),d("Zhao",20);
a.printname();
a.printage();
b.printname();
b.printage();
c.printname();
c.printage();
d.printname();
d.printage();
return 0;
}
输出结果
析构函数(Destructor)
在类的定义时,名称与类名相同,增加一个~,一般用于释放对象所占用的资源,在对象消失时调用。
析构函数也可以有多个。
如果没有手动写析构函数,编译器会生成一个默认析构函数,并调用。
class Student
{
public:
Student() //构造函数
{
cout << "调用构造函数"<< endl;
}
~Student()
{
cout << "调用析构函数" << endl;
}
};
int main()
{
Student A;
cout<<1;
}
在不存在额外操作的情况下,class会在创造他的代码结束后被清除,比如这里输出的最终结果就应该是“构造,1,析构”。