从c到c++(2)
1.类的定义
c++的struct是在c的struct类型上,增加了成员函数
c的struct可将一个概念或实体的所有属性组合在一起,描述同一类对象的共同属性
c++使struct不但包含数据,还包含函数用于访问或修改变量
#include <iostream>
#include <cmath>
using namespace std;
struct Date{
int d, m, y;
void init(int dd, int mm, int yy){
d = dd;
m = mm;
y = yy;
}
void print(){
cout << y << "-" << m << "-" << d << endl;
}
Date& add(int dd){
d = d + dd;
return *this; // this是指向这个函数的类型对象指针
// *this解引用,是这个函数的对象
// 这个函数返回的是自引用。可以实现链式调用
}
// 成员函数重载+=运算符实现更直观的add
Date& operator+= (int dd) {
d = d + dd;
return *this;
}
};
int main(){
Date day;
day.print();
day.init(4, 6, 1999);
day.add(1).add(1);
(day += 1) += 1;
day.print();
}
2.构造函数与析构函数
#include <iostream>
#include <cstring>
using namespace std;
struct Person{
int age;
char *name;
// 构造函数。注:构造函数可以重载
Person(char *n = "on_name", int a = 0){
int len = strlen(n);
// 申请内存
name = new char[len + 1]; // +1给\0留位置
strcpy(name, n); // 字符串拷贝
age = a;
cout << "构造完毕" << endl;
}
// 析构函数
virtual ~Person(){
// 释放内存 ,防止内存泄漏
delete[] name;
cout << "析构完毕" << endl;
}
};
int main(){
Person p("小明", 5);
cout << p.name << "--" << p.age << endl;
}
3.访问控制与接口
class比struct多了访问控制与接口
#include <iostream>
#include <cstring>
using namespace std;
// 把struct改成class之后要用public修饰才能达到和之前一样的效果,不然回报错,因为class里面的成员变量和成员函数默认是private的
class Person{
// public:之后的成员函数和成员变量是公开的
public:
int age;
char *name;
// 构造函数。注:构造函数可以重载
Person(char *n = "on_name", int a = 0){
int len = strlen(n);
// 申请内存
name = new char[len + 1]; // +1给\0留位置
strcpy(name, n); // 字符串拷贝
age = a;
cout << "构造完毕" << endl;
}
// 析构函数
virtual ~Person(){
// 释放内存 ,防止内存泄漏
delete[] name;
cout << "析构完毕" << endl;
}
};
int main(){
Person p("小明", 5);
cout << p.name << "--" << p.age << endl;
}
4.拷贝:拷贝构造函数
硬拷贝带来的问题
#include <iostream>
#include <cstring>
using namespace std;
class Person{
public:
int age;
char *name;
// 构造函数。注:构造函数可以重载
Person(char *n = "on_name", int a = 0){
int len = strlen(n);
// 申请内存
name = new char[len + 1]; // +1给\0留位置
strcpy(name, n); // 字符串拷贝
age = a;
cout << "构造完毕" << endl;
}
// 析构函数
virtual ~Person(){
// 释放内存 ,防止内存泄漏
delete[] name; // 由于硬拷贝,p和p1的name指向同一块内存,而它们的析构函数分别会执行一次,所以会对同一块内存释放两次 ,从而出错 ,解决方案如下
cout << "析构完毕" << endl;
}
// 解决上述硬拷贝带来的问题,重写拷贝构造函数,实现浅拷贝
Person(Person &p){
age = p.age;
// 让拷贝构造函数的成员不指向同一块内存,从而避免析构函数对同一块内存释放两次的问题
int len = strlen(p.name);
name = new char[len + 1]; // +1给\0留位置
strcpy(name, p.name); // 字符串拷贝
}
};
int main(){
Person p("小明", 5);
// 调用拷贝构造函数 ,如不重写该构造函数,属于硬拷贝
Person p1(p);
cout << p.name << "--" << p.age << endl;
cout << p1.name << "--" << p1.age << endl;
}
5.类模板:我们可以将一个类变成类模板或模板类,正如一个模板函数一样
#include <iostream>
using namespace std;
// 类模板实现数组存放所有的类型
template <class T>
class Array{
int size;
T *data;
public:
Array(int s){
// 数组长度
size = s;
// 数组的数据
data = new T[s];
}
// 析构函数
~Array(){
delete[] data;
}
// 运算符重载
T& operator [](int i){
if(i < 0 || i >= size){
cout << "err";
throw "out of index";
}
return data[i];
}
// 遍历数组
void show(){
for(int i = 0; i < size; i++){
cout << data[i] << endl;
}
}
};
int main(){
int n = 2;
// <int> 表示 T是int类型
Array<int> t(n);
t[0] = 1;
// 两次利用了运算符重载,实现了数组使用键赋值和获取值
t[1] = t[0] + 1;
// t[2] = 3; 会触发错误
t.show();
}
6.string
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
// string对象的初始化
string s("HELLO");
s = "DEMO"; // 赋值运算符
// 常量迭代器
string::const_iterator cii;
int ii = 0;
for(cii = s.begin(); cii != s.end(); cii++){
cout << ii++ << " " << *cii << endl;
}
// 向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)
// 跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。
vector<int>obj;//类模板的使用方法,创建一个向量存储容器 int
for(int i=0;i<10;i++) // push_back(elem)在数组最后添加数据
{
obj.push_back(i);
cout<<obj[i]<<",";
}
}
7.继承:一个派生类从1个或多个父类继承,既继承父类的属性和行为,但也有自己的特有属性和行为
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Person{
public:
string name;
void say(){
cout << "i am " << name;
}
};
class Teacher: public Person{
public:
Teacher(string n){
name = n;
}
};
int main(){
Teacher a("白白");
a.say();
}