C++课程笔记 类和对象
类概念
结构体:只要属性
类:有属性也有方法
c++可以省略struct c不行
#include<iostream>
using namespace std;
typedef struct queue1
{
int a;
queue1 q() {
queue1 q(2);
return q;
};
queue1()
{
}
queue1(int qa)
{
a = qa;
}
}q1;
int main()
{
queue1 Q1;
queue1 Qt=Q1.q();
cout << Qt.q().a<<endl;
q1 Q2(2);
cout << Q1.a<<endl;
cout << Q2.a;
}
struct内部成员默认公有,class默认私有。
public private不分上下
声明定义分离原因:
方便代码阅读
Q1.h:
#include<iostream>
#include<stdbool.h>
using namespace std;
class Cycle
{
public :
void Init(int n = 4);
int getr();
private:
int r;
};
class Point
{
public:
void Init(int a = 4,int b=4);
int geta();
int getb();
private:
int a;
int b;
};
void ifin(Cycle& c, Point& p);
源.cpp:
#define _CRT_SECURE_NO_WARNINGS 1
#include"Q1.h"
void Cycle::Init(int n) {
r = n;
}
int Cycle::getr() {
return r;
}
void Point::Init(int m, int n)
{
a = m;
b = n;
}
int Point::geta() {
return a;
}
int Point::getb() {
return b;
}
void ifin(Cycle& c,Point& p)
{
int d1 = p.geta() * p.geta() + p.getb() * p.getb();
int d2 = c.getr() * c.getr();
if (d1 > d2)
{
cout << "不在" << endl;
}
if (d1 <= d2)
{
cout << "在" << endl;
}
return;
}
test.cpp
#include"Q1.h"
int main()
{
Cycle c1;
Point p1;
ifin(c1, p1);
}
类和对象存储:
成员方法存储在公共区方法
成员变量按结构体空间计算
只有成员函数的类大小都是1
构造函数
构造函数完成初始化
class Date {
public:
Date(int year, int month)
{
_year = year;
_month = month;
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
/
Date d1(2019, 4);
d1.print();
}
class Date {
public:
Date(int year=2020, int month=2,int day=1)
{
_year = year;
_month = month;
_day = day;
}
Date()
{
_year = 2019;
_month = 2;
_day = 1;
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2021);
d1.print();
}
class Date {
public:
Date(int year=2020, int month=2,int day=1)
{
_year = year;
_month = month;
_day = day;
}
Date()
{
/* _year = 2019;
_month = 2;
_day = 1;*/
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.print();
}
全缺省构造可代替无参构造
class Stack
{
public:
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
_top = 0;
_capacity = 4;
}
void Push(int t)
{
_a[_top++] = t;
}
void Print()
{
for (int i=0;i<_top;i++)
{
cout << _a[i] << endl;
}
}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack s;
s.Push(1);
s.Push(2);
s.Print();
}
class A {
public:
A()
{
_a = 1;
cout << "A()构造函数" << endl;
}
private:
int _a;
};
class Date {
public:
/*Date(int year=2020, int month=2,int day=3)
{
_year = year;
_month = month;
_day = day;
}*/
//Date()
//{
///* _year = 2019;
// _month = 2;
// _day = 1;*/
//}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
A _A;
};
int main()
{
Date d1;
return 0;
}
默认构造函数内置类型不处理,自定义类型使用自定义类型默认构造函数。
用栈实现队列中,此类就不用写MyQueue构造函数,可以用MyQueue默认生成的,调用Stack默认构造函数。
释放时也会调用Stack默认析构函数,内置类型同样不会处理,自定义类型调用默认析构函数。
class Stack
{
public:
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
cout << "Stack 构造" << endl;
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
_top = 0;
_capacity = 4;
}
~Stack()
{
cout << "Stack 析构" << endl;
free(_a);
_a = nullptr;
_top = 0;
_capacity = 0;
}
void Push(int t)
{
_a[_top++] = t;
}
void Print()
{
for (int i=0;i<_top;i++)
{
cout << _a[i] << endl;
}
}
private:
int* _a;
int _top;
int _capacity;
A _A;
};
class MyQueue {
private:
Stack s1;
};
int main()
{
MyQueue m1;
return 0;
}
自定义类型构造被内置类型扰乱了
可以用一下c++11特性解决
class Date {
public:
/*Date(int year=2020, int month=2,int day=3)
{
_year = year;
_month = month;
_day = day;
}*/
//Date()
//{
///* _year = 2019;
// _month = 2;
// _day = 1;*/
//}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year=2019;
int _month=3;
int _day=3;
A _A;
};
不传参数就能调用的构造函数是默认构造
析构函数
malloc手动free后销毁
~Stack()
{
free(_a);
_a = nullptr;
_top = 0;
_capacity = 0;
}
return时调用析构函数
拷贝构造
class Date {
public:
Date(int year=2019, int month=2,int day=3)
{
_year = year;
_month = month;
_day = day;
}
Date(Date& d)
{
cout << "拷贝构造" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year=2019;
int _month=3;
int _day=3;
A _A;
};
void Func1(Date d)
{
cout << "Func1" << endl;
}
void Func2(Date& d) {
cout << "Func2" << endl;
}
int main()
{
Date d1;
Func1(d1);
Func2(d1);
return 0;
}
只要Func1调用了拷贝构造
拷贝构造前加const 为了避免错误更改原先对象
class Stack
{
public:
Stack(int top,int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
cout << "Stack 构造" << endl;
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
_top = 0;
_capacity = capacity;
}
~Stack()
{
cout << "Stack 析构" << endl;
free(_a);
_a = nullptr;
_top = 0;
_capacity = 0;
}
void Push(int t)
{
_a[_top++] = t;
}
void Print()
{
for (int i=0;i<_top;i++)
{
cout << _a[i] << endl;
}
}
private:
int* _a;
int _top;
int _capacity;
A _A;
};
int main()
{
Stack s(4,4);
Stack s2(s);
return 0;
}
默认拷贝构造是浅拷贝,函数释放后会free两次,会报错
自定义深拷贝:
class Stack
{
public:
Stack(int top,int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
cout << "Stack 构造" << endl;
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
_top = 0;
_capacity = capacity;
}
Stack(const Stack& s)
{
_a = (int*)malloc(sizeof(int) * s._capacity);
{
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
}
memcpy(_a, s._a, sizeof(int) * s._top);
_top = s._top;
_capacity = s._capacity;
}
~Stack()
{
cout << "Stack 析构" << endl;
free(_a);
_a = nullptr;
_top = 0;
_capacity = 0;
}
void Push(int t)
{
_a[_top++] = t;
}
void Print()
{
for (int i=0;i<_top;i++)
{
cout << _a[i] << endl;
}
}
private:
int* _a;
int _top;
int _capacity;
//A _A;
};
int main()
{
Stack s(0,4);
s.Push(1);
s.Push(2);
s.Print();
Stack s2(s);
return 0;
}
不用写拷贝构造:
运算符重载
class Date {
public:
Date(int year=2019, int month=2,int day=3)
{
_year = year;
_month = month;
_day = day;
}
Date(Date& d)
{
cout << "拷贝构造" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
bool operator ==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
private:
int _year=2019;
int _month=3;
int _day=3;
A _A;
};
int main()
{
Date d1(2019,3,2);
Date d2(2020, 4, 3);
cout << (d1 == d2) << endl;
//加括号避免运算符优先级问题
return 0;
}
在 C++ 中,运算符重载函数
bool operator==(const Date& d)
只需要一个参数的原因是,它实际上是在定义一个成员函数。成员函数隐含地有一个指向当前对象(即this
指针)的参数,因此只需要提供与当前对象进行比较的另一个Date
对象作为参数。具体解释:
隐含的
this
指针: 当你在类内部定义一个成员函数时,这个函数可以访问类的成员变量和成员函数。每个成员函数都有一个隐含的this
指针,它指向调用该函数的对象。operator==
作为成员函数时,隐含的this
指针会指向调用==
运算符的那个对象。例如,假设有两个
Date
对象d1
和d2
,当你写d1 == d2
时,编译器实际上会将其转换为d1.operator==(d2)
。此时,this
指针指向d1
,而d2
作为参数传递给operator==
函数。参数个数:
成员函数重载: 对于成员函数形式的运算符重载,
==
只需要一个参数,因为this
指针隐式地传递了调用该运算符的对象。
bool operator ==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
bool operator >=(const Date& d)
{
计算日期程序:
class Date {
public:
Date(int year=2019, int month=2,int day=3)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
cout << "拷贝构造" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
//Date()
//{
///* _year = 2019;
// _month = 2;
// _day = 1;*/
//}
int GetMonthDay(int year, int month)
{
static int monthday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && (year % 4 == 0 && year % 100 != 0 )|| year % 400 == 0)
{
return 29;
}
return monthday[month];
}
Date operator+=(int day)
{
_day = day + _day;
int monthday = GetMonthDay(_year, _month);
while (_day > monthday)
{
++_month;
if (_month == 13)
{
_year++;
_month = 1;
}
_day = _day - monthday;
monthday = GetMonthDay(_year, _month);
}
return *this;
}
Date& operator+(int day)
{
Date ret(*this);
ret += (day);
return ret;
}
void print()
{
cout << _year << " " << _month << " " << _day << endl;
}
bool operator ==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
bool operator >=(const Date& d)
{
return *this == d || *this > d;
}
private:
int _year=2019;
int _month=3;
int _day=3;
A _A;
};
int main()
{
Date d1(2024,9,10);
Date d2(2019, 3, 2);
cout << (d1 == d2) << endl;
cout << (d1 > d2) << endl;
cout << (d1 >= d2) << endl;
d1 += 100000;
Date d3(d1+10);
return 0;
}
Date& operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
//return d会出现权限放大
}
int main()
{
Date d1(2024,9,10);
Date d2(2019, 3, 2);
d1 = d2;
return 0;
}
不显示写赋值重载,默认生成的,对自定义类型会浅拷贝
显示写重载,先释放,再开辟空间。
Stack& operator=(const Stack& s)
{
if(this!=&s)
{
free(_a);
_a = (int*)malloc(sizeof(int) * s._capacity);
if (_a == nullptr)
{
perror("malloc fail");
exit(-1);
}
memcpy(_a, s._a, sizeof(int)*s._top);
_top = s._top;
_capacity = s._capacity;
return *this;
}
}
运算符重载目的是让自定义类型对象可以用运算符。
this指针默认抢了第一个位置
在.h中定义的Print在两个cpp文件都有定义,链接符号表时出现问题
改成静态可以解决问题 不进符号表
声明定义分离也可以解决问题
.h没有定义,不会进符合表
内敛函数在调用的地方直接展开,也可以解决问题。
友元函数:
友元函数没有this指针。 在类中任意位置可以进行友元声明
可以不用去掉private
权限放大只出现在指针和引用上。
this指针默认是不能修改的。
初始化列表
_m不显示写构造,会调用默认构造
类C没有默认构造:
类C有默认构造:
i给rd引用 i给rd的是临时变量,临时变量具有常性。
加入explicit就不允许隐式类型转换发生了。
int N = 0;
class A {
public:
A(int a)
:_a(a)
{
N++;
cout << "A()构造函数" << endl;
}
A(const A& a)
:_a(a._a)
{
N++;
cout << "A()拷贝构造函数" << endl;
}
private:
int _a;
};
void Func(A a)
{
}
int main()
{
A a1(1);
A a2 = 2;
A a3 = a1;
Func(a3);
cout << N<<endl;
}
A a3=a1 构造+拷贝构造被优化成了拷贝构造
A::N,指定类域会到命名空间中找, 不指定会先到局部再到全局中找,找不到会报错。
class A {
public:
A(int a=1)
:_a(a)
{
N++;
cout << "A()构造函数" << endl;
}
A(const A& a)
:_a(a._a)
{
N++;
cout << "A()拷贝构造函数" << endl;
}
int GetN()
{
return N;
}
private:
int _a=1;
static int N ;
};
int A::N = 0;
int main()
{
A a1;
A a2 = 2;
A a3 = a1;
//Func(a3);
cout <<a3.GetN()<<endl;
cout << a2.GetN() << endl;
}
应该n数组构造n个对象
友元类:
class Time {
friend class Date;
public:
Time(int hour=1, int minute=1, int second=1)
:_hour(hour)
, _minute(minute)
, _second(second)
{
}
private:
int _hour;
int _minute;
int _second;
};
class Date {
public:
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
Date(int year=2019, int month=1,int day=3)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
cout << "拷贝构造" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void SetTime(int hour, int minute, int second)
{
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
private:
int _year=2019;
int _month=3;
int _day=3;
//A _A;
Time _t;
};
内部类:
class A {
public:
A(int a=1)
:_a(a)
{
N++;
cout << "A()构造函数" << endl;
}
A(const A& a)
:_a(a._a)
{
N++;
cout << "A()拷贝构造函数" << endl;
}
class B {
public:
void foo()
{}
};
static int GetN()
{
return N;
}
private:
int _a=1;
static int N ;
};
int main(){
A::B ab1;
ab1.foo();
}
匿名对象:
创建完直接销毁
引用的话需要加const 因为传的是临时变量 具有常性