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++的基础知识。