C++学习第四天
创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。
提示:以下是本篇文章正文内容,下面案例可供参考
一、计算类对象的大小
#include<iostream>
using namespace std;class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//private:int _year; // 声明int _month;int _day;
};int main()
{cout << sizeof(Date) << endl;return 0;
}
计算类对象大小的时候不会把函数也计算进去。
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//private:int _year; // 声明int _month;int _day;
};int main()
{cout << sizeof(Date) << endl;Date d1;Date d2;d1.Print();d2.Print();return 0;
}
call的地址是一样的。
类对象的存储方式:只保存成员变量,成员函数存放在公共代码区。
#include<iostream>
using namespace std;
class A1
{public:void f1() { }private:int _a;
};
// 类中仅有成员函数
class A2 {
public:void f2() {}
};
// 类中什么都没有---空类
class A3
{};int main()
{cout << sizeof(A1) << endl;// 分配1byte,不存储数据,只是占位,表示对象存在过cout << sizeof(A2) << endl;cout << sizeof(A3) << endl;return 0;
}
#include<iostream>
using namespace std;
class A2 {
public:void f2() {}
};int main()
{//如果不分配字节,怎么表示下面两个不同对象的地址?A2 aa2;A2 aaa2;cout << &aa2 << endl;cout << &aaa2 << endl;return 0;
}
二、 结构体内存对齐规则
#include<iostream>
using namespace std;
class A1
{public:void f1() { }private:char _ch;int _a;
};int main()
{cout << sizeof(A1) << endl;return 0;
}
三、this指针
void Init(int year, int month, int day)
{_year = year;_month = month;_day = day;
}等价于
void Init(Date* this,int year, int month, int day)
{this->_year = year;this->_month = month;this->_day = day;
}Date d1;
d1.Init(2023, 7, 20);等价于
Date d1;
d1.Init(&d1,2023, 7, 20);this指针的类型:类型* const,即成员函数中,不能给this指针赋值。严格来说,
上面this前面应该加上const
#include<iostream>
using namespace std;class Date
{
public:// this在实参和形参位置不能显示写// 但是在类里面可以显示的用void Init(int year, int month, int day){cout << this << endl;_year = year;_month = month;_day = day;}void Print(){cout << this << endl;cout << _year << "/" << _month << "/" << _day << endl;}private:int _year; // 声明int _month;int _day;
};int main()
{Date d1;d1.Init(2023, 7, 20);d1.Print();Date d2;d2.Init(2023, 7, 21);d2.Print();return 0;
}
函数Init()和函数Print()中的this是不一样的,不是同一个变量,虽然他们打印的值相同,但是形参是取决于实参的。
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){cout << this << endl;_year = year;_month = month;_day = day;//可以在这里调用Print();Print();//也可以写成this->Print();}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year; // 声明int _month;int _day;
};int main()
{Date d1;d1.Init(2023, 7, 20);return 0;
}
问题1:
下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}
p - >Print();这句代码转成汇编指令,调用函数,这个函数不用去p指向的对象里面去找Print()的地址,成员函数的地址不存在对象里面。找Print()的地址:编译的时候在公共代码区拿Print()的名字去找到地址,call这个地址,p没有解引用,然后还要传递this指针,把p传给this指针。
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;(*p).Print();return 0;
}
函数Print()不在对象里面,不需要解引用,结果与上面一样。
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "Print()" << endl;}
//private:int _a;
};int main()
{A* p = nullptr;p->Print();p->_a;return 0;
}
p->a中也没有解引用,可以正常运行;因为使用的编译器比较新,自动优化了,如果在老的编译器运行,可能失败。
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "Print()" << endl;}
//private:int _a;
};int main()
{A* p = nullptr;p->Print();p->_a = 1;return 0;
}
解引用了
问题2:
下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
#include<iostream>
using namespace std;class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->PrintA();return 0;
}
cout << _a << endl;这里会变成this->_a去访问,而this是空。
问题3:
this指针存在哪里(栈 堆 静态区 常量区)?
答:this是一个形参,一般是存在栈帧里面。VS下面一般会用ecx寄存器直接传递。
四、c++实现Stack
#include<iostream>
#include<assert.h>
using namespace std;//数据和方法是封装在一起的,严格管控的。
class Stack
{
public:/*Stack(){a = nullptr;top = capacity = 0;}*/Stack(size_t n = 4) //构造函数{if (n == 0){a = nullptr;top = capacity = 0;}else{a = (int*)malloc(sizeof(int) * n);if(a == nullptr){perror("realloc fail");exit(-1);}top = 0;capacity = n;}}// 成员函数//void Init()//{// a = nullptr;// top = capacity = 0;//}void Push(int x){if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);if (tmp == nullptr){perror("realloc fail");exit(-1);}if (tmp == a){cout << capacity << "原地扩容" << endl;}else{cout << capacity << "异地扩容" << endl;}a = tmp;capacity = newcapacity;}a[top++] = x;}int Top(){return a[top - 1];}void Pop(){assert(top > 0);--top;}void Destroy(){free(a);a = nullptr;top = capacity = 0;}bool Empty(){return top == 0;}private:// 成员变量int* a;int top;int capacity;
};int main()
{Stack st1;st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);while (!st1.Empty()){cout << st1.Top() << " ";st1.Pop();}cout << endl;st1.Destroy();//Stack st2(1000);Stack st2;for (size_t i = 0; i < 1000; i++){st2.Push(i);}while (!st2.Empty()){cout << st2.Top() << " ";st2.Pop();}cout << endl;st2.Destroy();return 0;
}
五、类的6个默认成员函数
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
C语言结构体不支持成员函数,但C++结构体支持,其class与struct本质没有区别,唯一区别 在于默认时class的访问属性为私有,struct为公有。
六、构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
#include<iostream>
using namespace std;class Date
{
public:/*Date(){cout << "Date()" << endl;_year = 1;_month = 1;_day = 1;}*///Date(int year, int month, int day)//{// _year = year;// _month = month;// _day = day;//}Date(int year = 1, int month = 1, int day = 1) //全缺省函数{_year = year;_month = month;_day = day;}/*void Init(int year, int month, int day){_year = year;_month = month;_day = day;}*/void Print(){//cout << this << endl;cout << _year << "/" << _month << "/" << _day << endl;}private:int _year; // 声明int _month;int _day;
};int main()
{// 不能这么写/*Date d1();d1.Print();*/Date d1;// 调用无参构造函数d1.Print();Date d2(2023, 7, 20);// 调用带参的构造函数d2.Print();Date d3(2023);d3.Print();Date d4(2023, 7);d4.Print();return 0;
}
构造函数,也是默认成员函数,我们不写,编译器会自动生成
编译生成的默认构造的特点:
1、我们不写才会生成,我们写了任意一个构造函数就不会生成了
2、内置类型的成员(int、double、指针......)不会处理
#include<iostream>
using namespace std;class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year ; // 声明给的缺省值int _month ;int _day;
};int main()
{Date d1;d1.Print();return 0;
}
但是:C++11,声明支持给缺省值
#include<iostream>
using namespace std;class Date
{
public://Date(int year = 1, int month = 1, int day = 1)//{// cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;// _year = year;// _month = month;// _day = day;//}Date(){_month = 2;_day = 2;}void Print(){//cout << this << endl;cout << _year << "/" << _month << "/" << _day << endl;}private:int _year = 1; // 声明给的缺省值int _month = 1;int _day = 1;
};int main()
{// 构造函数,也是默认成员函数,我们不写,编译器会自动生成Date d1;d1.Print();return 0;
}
3、自定义类型的成员才会处理,回去调用这个成员的默认构造函数
#include<iostream>
#include<assert.h>
using namespace std;class Stack
{
public:Stack(size_t n = 4){cout << "Stack(size_t n = 4)" << endl;if (n == 0){a = nullptr;top = capacity = 0;}else{a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("realloc fail");exit(-1);}top = 0;capacity = n;}}void Push(int x){if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);if (tmp == nullptr){perror("realloc fail");exit(-1);}if (tmp == a){cout << capacity << "原地扩容" << endl;}else{cout << capacity << "异地扩容" << endl;}a = tmp;capacity = newcapacity;}a[top++] = x;}int Top(){return a[top - 1];}void Pop(){assert(top > 0);--top;}void Destroy(){free(a);a = nullptr;top = capacity = 0;}bool Empty(){return top == 0;}
private:// 成员变量int* a;int top;int capacity;
};// 两个栈实现一个队列
class MyQueue
{
private:Stack _pushst;Stack _popst;//Date* _ptr;//int _size;
};int main()
{MyQueue mq;return 0;
}
总结:一般情况都需要我们自己写构造函数,决定初始化方式
成员变量全是自定义类型,可以考虑不写构造函数
问题:
七、析构函数
1.定义
与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
2.特性
#include<iostream>
#include<assert.h>
using namespace std;class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day << endl;}~Date(){cout << "~Date()" << endl;}
private:int _year = 1; int _month = 1;int _day = 1;
};class Stack
{
public:Stack(size_t n = 4){cout << "Stack(size_t n = 4)" << endl;if (n == 0){a = nullptr;top = capacity = 0;}else{a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("realloc fail");exit(-1);}top = 0;capacity = n;}}~Stack(){cout << "~Stack()" << endl;free(a);a = nullptr;top = capacity = 0;}void Push(int x){if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);if (tmp == nullptr){perror("realloc fail");exit(-1);}if (tmp == a){cout << capacity << "原地扩容" << endl;}else{cout << capacity << "异地扩容" << endl;}a = tmp;capacity = newcapacity;}a[top++] = x;}int Top(){return a[top - 1];}void Pop(){assert(top > 0);--top;}bool Empty(){return top == 0;}
private:// 成员变量int* a;int top;int capacity;
};// 两个栈实现一个队列
class MyQueue
{
private:Stack _pushst;Stack _popst;//Date* _ptr;//int _size;
};int main()
{// 后定义,先析构Date d1;Date d2;Stack st1;Stack st2;MyQueue mq;return 0;
}
八、符号匹配问题
#include<iostream>
#include<assert.h>
using namespace std;class Stack
{
public:Stack(size_t n = 4){if (n == 0){a = nullptr;top = capacity = 0;}else{a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("realloc fail");exit(-1);}top = 0;capacity = n;}}~Stack(){free(a);a = nullptr;top = capacity = 0;}void Push(int x){if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);if (tmp == nullptr){perror("realloc fail");exit(-1);}a = tmp;capacity = newcapacity;}a[top++] = x;}int Top(){return a[top - 1];}void Pop(){assert(top > 0);--top;}bool Empty(){return top == 0;}
private:// 成员变量int* a;int top;int capacity;
};bool isValid(const char* s) {Stack st;while (*s){if (*s == '[' || *s == '(' || *s == '{'){st.Push(*s);++s;}else{// 不匹配if (st.Empty())return false;char top = st.Top();st.Pop();// 不匹配if ((*s == ']' && top != '[')|| (*s == ')' && top != '(')|| (*s == '}' && top != '{')){return false;}++s;}}return st.Empty();
}int main()
{cout << isValid("[[]]()()") << endl;cout << isValid("[[]]]") << endl;return 0;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了c++的基础知识。