这是一份记录一下学习c++的笔记,比较杂乱。
随机数种子
#include
//用时间制作的随机数种子
srand((using int)time(MULL));
rand()%61;//0~60取值
内存分区模型:代码区、全局区
代码区:程序执行前,存放cpu机器指令,共享,只读
全局区:程序执行前,全局变量,静态变量(static),常量(字符串常量,const修饰的全局变量)
栈区:程序执行后,局部变量,形参数据(由编译器开辟,函数执行后自动释放,要注意不能返回局部变量的地址)
堆区:程序执行后,由程序员开辟和释放,new出来的数据返回该数据类型的指针,指针的局部变量放在栈区,数据开辟在堆区存放。注意怎么开辟数组类型new int [10];释放 delete [] arry;
引用
给变量取别名:数据类型 &别名 = 原名
引用要初始化,不可以更改,操作的一直都要是同一块内存
引用传递,实参可以修饰形参与地址传递有一样的效果
不要返回局部变量的引用,返回引用的函数可以作为左值 int& test(); test()=1000;
引用本质是指针常量,值可以改,指向不能改 int * const ref= &a等价与 int& ref = a;
常量引用,const int& a = 10;等价于 int temp = 10; int & a = temp;使用在于修饰形参,防止误修改
函数提高
函数的默认参数:1.参数可以有默认值,但是往后的参数都要有2.函数声明和实现只能有一个有默认值
函数的占位参数:void func(int a;int),也可以有默认值void func(int a;int = 10)
函数的重载:1.作用域相同2.参数的个数,顺序,类型不同3.返回值不能作为条件。引用可以作为重载的条件void test(int &a);void test(const int &a);遇到默认参数如果是void test(int a);和如果是void test(int a,int b=10);调用可能会出现二义性,如果是void test(int a);和void test(const int &a);也会出现二义性。二义性:编译器不知道用哪个函数
12.23今天先到这,明天学一下类和对象--------------------------------------------------------------------------
c++三大特性:封装,继承,多肽
封装:设计类的时候,属性和行为写在一起表现事物。实例化是通过一个类创建具体的对象。属性(成员属性,成员变量)、行为(成员函数,成员方法)
关于权限:public(类内类外都可以访问)protected(类内可以,类外不行,子类可以)private(类内可以,类外不行,子类也不行)
struct的默认权限是public,class的默认权限是private
struct C1
{
int m_age;//公共权限
};
class C1
{
int m_age;//私有权限
};
成员属性私有化,可以用方法对其控制读写权限
class Person
{
private:
string m_name;
int m_age;
public:
void setName(string name)//通过set方法类外设置
{
m_name = name;
}
void getName()//通过get方法类外得到
{
return m_name;
}
};
构造函数和析构函数
特点:没有返回值和类同名,构造函数可重载析构函数不行,会自动调用一次,没有写程序也还会自己增加。析构前加~
构造函数分类:有参和无参(默认构造)、普通和拷贝(拷贝的话要用const 类命 & 变量名)
调用构造函数:
括号法
Person p1;//无参构造
Person p2(10);//有参构造
Person p3(p1);//拷贝构造
//注意无参构造不能加(),会被误会是函数 Person p();是错误的
显示法
Person p1;//无参构造
Person p2 = Person(10);//有参构造
Person p3= Person(p2);//拷贝构造
//匿名对象会马上被回收无法使用 Person(10);
//注意不要用匿名对象调用拷贝构造会被误会重定义 Person(p3) = Person p3;
隐式转换法
Person p1;//无参构造
Person p2 = 10;//有参构造
Person p3= p2;//拷贝构造
拷贝构造函数的调用:
复制已有的对象信息
Person p2(10);
Person p3(p1);//把p2的值都拷贝一份
传值的方式调用
void test(Person p)//拷贝一份
{
}
void copy()
{
Person p1;
test(p1);
}
返回值的方式调用
Person test()
{
Person p1;//局部变量函数结束被销毁
return p1;//重新拷贝一份
}
void copy()
{
Person p = test();//p和函数里面的p1地址不一样
}
构造函数的调用规则
默认提供无参构造函数、拷贝构造函数(值拷贝)、析构函数
如果通过有参构造,不提供无参构造只通过拷贝构造;如果通过拷贝构造,有参和无参构造都不提供
深拷贝与浅拷贝
主要是拷贝构造函数的问题,浅拷贝只是简单的值拷贝,如果有指针开辟内存会出现析构重复释放同一个内存地址的问题,要用深拷贝来解决这个问题。深拷贝:在拷贝构造函数里也要重新开辟一个内存
Person(const Person& p)
{
m_height = new int(*p.m_height);//重新开辟内存,深拷贝
}
~Person()
{
if(m_height!=NULL)
delete m_height;//析构函数要释放内存
}
构造函数初始化列表
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
}
类中有类对象构造和析构的顺序是什么样的,先构造的后析构
class A
{
};
class B
{
A a;//类中对象先构造,自身的类先析构
};
12.24今天先到封装,明天学一下继承吧!--------------------------------------------------------------------------
静态成员
静态成员变量:所有数据都共享一份内存;编译阶段就分配内存(全局区);类内声明类外初始化,有访问权限。可以通过对象调用,也可以通过类名调用
class Person
{
static int m_A;//类内声明
private:
static int m_B;//私有变量类外无法访问
}
int Person::m_A = 100;//类外初始化
void test01()
{
Person p;
p.m_A;//对象调用
Person::m_A;//类名调用
}
静态成员函数:所有对象都共用一个函数,只能使用静态成员变量(因为非静态成员变量对象不一致,无法在类内使用),有访问权限。可以通过对象调用,也可以通过类名调用
class Person
{
static int m_A;//类内声明
int m_C;
static void func()
{
m_A = 100;//可以修改因为都是一份数据
m_C = 200;//不可以修改因为对象无法确定
}
private:
static void func1();//私有函数类外无法访问
};
void test01()
{
Person p;
p.func();//对象调用
Person::func();//类名调用
}
成员变量和成员函数分开存储,只有非静态成员变量才是属于类的对象上,空对象占一个字节(区分空对象占内存的位置)
class Person
{
int m_A;//非静态成员变量,属于类的对象
static int m_B;//静态成员变量,不属于类的对象
void funC();//非静态成员函数,不属于类的对象
static void funA();//静态成员函数,不属于类的对象
};
this指针的用途:解决命名冲突;返回*this,可以实现链式编程
class Person
{
int age;
void setAge(int age)
{
age = age;//形参与成员变量同名,无法进行区分
this->age = age;//可以解决命名冲突,指向被调用成员函数所属对象
}
Person addAge(Person p)//返回值会拷贝一份已经不是本身了
{
this->age = p.age;//年龄追加
return *this;
}
Person& addAge(Person p)//返回引用一直都是自己那一份
{
this->age = p.age;//年龄追加
return *this;
}
};
void test()
{
Person p1(10);
Person p2(10);
p2.addAge(p1).addAge(p1).addAge(p1);//可以实现链式编程
}
注意:this空指针无法访问成员变量
void test()
{
Person *p = NULL;
p.getAge();
}
class Person
{
int age;
void getAge()
{
if(this==NULL)//指针如果为空无法访问变量,提高健壮性
{
return;
}
cout<<age;
}
};
const修饰成员函数:this指针的本质是指针常量,值可以改这种指向不能修改,再再函数本身加上const限定的话称为常函数,值也会不能修改。如果非要修改的话,在变量前加上mutable才可以修改。const修饰对象称为常对象,常对象只能调用常函数限定只读,因为要保持成员变量值也不能修改的特性,常对象中只能修改mutable限定的特殊变量。
class Person
{
int age;
mutable int year;
void setAge() const//加上const限定 const Person *const this;//指针指向和值都不能修改
{
year = 2024;//可以修改,因为有mutable
}
void getAge();
};
void test()
{
const Person p;
p.getAge();//无法调用,常对象只能调用常函数
p.setAge();//可以调用常函数
p.age = 100;//无法修改
p.year= 100;//可以修改,因为有mutable
}
友元函数:全局函数做友元,类做友元,类内的成员函数做友元,都是加friend,可以访问本类中的私有变量
全局函数
class Bulid
{
friend void visit();//告诉编译器这是好朋友可以访问私有变量
void Bulid()
{
m_SettingRoom = "客厅"
m_BedRoom= "卧室"
}
public:
string m_SettingRoom;
private:
string m_BedRoom;
};
void visit()
{
Bulid b;
cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
}
类
class Bulid
{
friend class GoodFriend;//告诉编译器这是好朋友类可以访问私有变量
void Bulid()
{
m_SettingRoom = "客厅"
m_BedRoom= "卧室"
}
public:
string m_SettingRoom;
private:
string m_BedRoom;
};
class GoodFriend
{
GoodFriend()
{
b = new Bulid;//new出来一个类
}
void visit()
{
cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
}
Bulid b;
};
类的成员函数
class Bulid
{
friend void GoodFriend::visit();//告诉编译器这是类下的好朋友函数可以访问私有变量
void Bulid()
{
m_SettingRoom = "客厅"
m_BedRoom= "卧室"
}
public:
string m_SettingRoom;
private:
string m_BedRoom;
};
class GoodFriend
{
GoodFriend()
{
b = new Bulid;//new出来一个类
}
void visit()
{
cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
}
Bulid b;
};
运算符重载:operate+(),operate<<(),operate++(),operate++(int),operate=(),operate==(),operate!=(),operate()(),运算符重载可以在类内通过成员函数,也可以通过全局函数。对于已有的数据类型不能随意重载,也不要更改原有的运算规则
operate+()
class Person
{
int age;
Person operate+(Person &p)//通过成员函数重载+,要不要返回引用只是要看要不要对自身数据进行下一步操作
{
Person temp;
temp.age = this->age+p.age;
return temp;
}
};
Person operate+(Person &p1,Person &p2)//通过全局函数重载+
{
Person temp;
temp.age = p1.age+p2.age;
return temp;
}
Person operate+(Person &p1,int num)//函数重载的版本
{
Person temp;
temp.age = p1.age+num;
return temp;
}
void test()
{
Person p1;
p1.age = 10;
Person p2;
p2.age = 10;
Person p3 = p1+p2;//成员函数本质Person p3 = p1.operate+(p2);
Person p3 = p1+p2;//全局函数本质Person p3 = operate+(p1,p2);
Person p3 = p1+10;
}
operate<<(),因为成员函数重载会出现p.operate<<(cout)简化是p<<cout的结构,所以这里使用全局函数重载,输出自定义类型
class Person
{
friend ostream& operate<<(ostream &cout,Person &p1);//全局友元可以访问私有变量
private:
int age;
Person(int age)
{
this->age = age;
}
Person operate+(Person &p)//通过成员函数重载+,要不要返回引用只是要看要不要对自身数据进行下一步操作
{
Person temp;
temp.age = this->age+p.age;
return temp;
}
};
ostream& operate<<(ostream &cout,Person &p1)//通过全局函数重载+,本质operat<<(cout,p)简化cout<<p
{
cout<<p1.age;
return cout;
}
void test()
{
Person p1(10);
cout<<p1<<endl;
}
operate++(),operate++(int),自增运算符重载
class MyInterer
{
friend ostream& operate<<(ostream &cout,Person &p1);//全局友元可以访问私有变量
public:
MyInterer()
{
num = 0;
}
//重载前置++运算符,返回引用是为了一直对一个数据进行操作
MyInterer& operate++()
{
num++;
return *this;//返回自身
}
//重载后置++运算符,int是占位参数表示区分前置和后置,返回值因为是局部变量要不会非法操作
MyInterer operate++(int)
{
MyInterer my = *this;//先记录原本的
num++;//再增加
return my;//再返回
}
private:
int num;
}
ostream& operate<<(ostream &cout,Person &p1)//通过全局函数重载+,本质operat<<(cout,p)简化cout<<p
{
cout<<p1.age;
return cout;
}
void test01()
{
MyInterer my1;
cout<<++(++my1)<<endl;//返回引用一直对自己操作 2
cout<my1<<endl;//已经加上 2
}
void test02()
{
MyInterer my2;
cout<<my2++<<endl;//0 不会(my2++)++这种写法因为是返回值不可修改
cout<my2<<endl;//1
}
operate=() c++编译器还会给类增加第四个函数是operate=,进行值拷贝。所以还是会出现浅拷贝的问题,重复释放同一个堆区的内容,要用深拷贝解决
class Person
{
int *m_age;
Person(int age)
{
m_age = new int(age);//重新开辟内存,深拷贝
}
~Person()
{
if(m_age !=NULL)
{
delete m_age ;//析构函数要释放内存,这里就会暴露浅拷贝出现的问题所以要重载operate=使用深拷贝
m_age = NULL;
}
}
Person& operate=(Person &p)
{
m_age = p.age;//编译器本身是值拷贝
if(m_age !=NULL)//先判断原本有没有数据,有的话先清空
{
delete m_age ;
m_age = NULL;
}
m_age = new int(*p.age);//重新开辟内存,深拷贝
return *this;//返回自身的引用才能连续操作
}
};
void test()
{
Person p1(10);
Person p2(20);
Person p3(30);
p3 = p2 = p1;
}
operate==(),operate!=()关系运算符重载,自定义数据类型判断
class Person
{
int age;
bool operate ==(Person &p)
{
if(this->age == p.age)
{
return true;
}
return false;
}
bool operate !=(Person &p)
{
if(this->age == p.age)
{
return false;
}
return true;
}
};
void test()
{
Person p1(10);
Person p2(20);
if(p1==p2)
{
cout<<"相等"<<endl;
}
else
{
cout<<"不相等"<<endl;
}
if(p1!=p2)
{
cout<<"不相等"<<endl;
}
else
{
cout<<"相等"<<endl;
}
operate()(),很像函数调用所以叫仿函数,比较灵活没有固定写法
class MyPrint
{
void operate()(string s)
{
cout<<s<<endl;
}
};
class MyAdd
{
int operate()(int a,int b)
{
return a+b;
}
};
void test01()
{
MyPrint myprint;
myprint("test");//特别像函数调用
}
void test02()
{
MyAdd myadd;
myadd(100,100);
cout<<MyAdd()(100,100)<<endl;//匿名函数对象
}
12.26重载有好多东西啊,只能明天再学继承和多肽了!--------------------------------------------------------------------------
标签:p1,int,void,c++,学习,Person,operate,age From: https://blog.csdn.net/qq_45080494/article/details/144658045