C++学习二
2021-03-17 本文已影响0人
芳心之纵火犯
一、构造函数和析构函数
#include <iostream>
#include <string.h>
using namespace std;
class Student {
// 构造函数
public:
// 空参数构造函数
Student() {
cout << "空参数构造函数" << endl;
}
// 一个参数的构造函数
//Student(char *name){
// cout << "一个参数的构造函数" << endl;
// this->name = name;
//}
// :Student(name, 87) 等价 1.调用两个参数的构造函数, 2.再调用当前函数
// 先调用两个参数的,再调用一个的
Student(char *name) :Student(name, 87) {
cout << "一个参数的构造函数" << endl;
this->name = name;
}
// 系统源码中是写的
// :name(name) 等价 this->name = name;
/*Student(char * name) :name(name) {
cout << "一个参数的构造函数" << endl;
}*/
// 两个参数的构造函数
Student(char *name, int age) {
// this->name = name;
// 堆区
this->name = (char *) (malloc(sizeof(char *) * 10));
strcpy(this->name, name);
this->age = age;
cout << "两个参数的构造函数" << endl;
}
// 析构函数 Student对象的,临终遗言,Student对象被回收了,你做一些释放工作
// delete stu 的时候,我们的析构函数一定执行
// free不会执行析构函数,也意味着,你没法在析构函数里面,做释放工作, malloc也不会调用构造函数
~Student() {
cout << "析构函数" << endl;
// 必须释放 堆区开辟的成员
if (this->name) {
free(this->name);
this->name = NULL; // 执行NULL的地址,避免出现悬空指针
}
}
// 私有属性
private:
char *name;
int age;
// 公开的 set get 函数
public:
int getAge() {
return this->age;
}
char *getName() {
return this->name;
}
void setAge(int age) {
this->age = age;
}
void setName(char *name) {
this->name = name;
}
};
int main() {
// TODO =========== 下面是栈区 开辟空间的
/*Student stu; // 调用 空参数构造函数
stu.setAge(34);
stu.setName("李元霸");
cout << "name:" << stu.getName() << ", age:" << stu.getAge() << endl;*/
// Student stu("雄霸", 30);
/*Student stu("李连杰");
cout << "name:" << stu.getName() << ", age:" << stu.getAge() << endl;*/
// TODO =========== 下面是堆区 开辟空间的 堆区必须手动释放,否则内存占用越来
// *stu ->:调用一级指针的成员
Student *stu = new Student("杜子腾", 26);
cout << "name:" << stu->getName() << ", age:" << stu->getAge() << endl;
delete stu;
// malloc 你的构造函数都没有调用,这个不行的
/*Student *stu2 = (Student*) malloc(sizeof(Student));
free(stu2);*/
return 0;
}
二、拷贝构造函数
struct Person {
int age;
char *name;
};
// TODO = 号的意义 隐士代码,引出 拷贝构造函数
/*
int main() {
Person person1 = {100, "张三丰"};
// = 你看起来,没有什么特殊,隐士的代码:你看不到 C/C++编译器 会把p1的成员值赋值给p2成员
Person person2 = person1;
//地址不一样
cout << &person1 << endl;
cout << &person2 << endl;
cout << person2.name << ", " << person2.age << endl;
// 对象 对象1=对象2 默认的 拷贝构造函数 如图1
return 0;
}*/
拷贝构造函数01.png
#include <iostream>
#include <string.h>
using namespace std;
class Student {
public:
Student() { cout << "空参数构造函数" << endl; }
// 两个参数的构造函数
Student(char *name, int age) : name(name), age(age) {
cout << "两个参数构造函数" << endl;
}
// 析构函数:不能有参数
// ~Student(char * name) { }
~Student() {
cout << "析构函数" << endl;
}
// 拷贝构造函数,它默认有,我们看不到,一旦我们写拷贝构造函数,会覆盖她
// 对象1 = 对象2
// 覆盖拷贝构造函数
Student(const Student & student) { // 常量引用:只读的,不让你修改
cout << "拷贝构造函数" << endl;
// 我们自己赋值
// 为什么要自己赋值,自己来控制,就可以 例如:-10
this->name = student.name;
this->age = student.age - 10;
cout << "自定义拷贝构造函数 内存地址 " << &student << endl;
}
// 私有属性
private:
char *name;
int age;
// 公开的 set get 函数
public:
int getAge() {
return this->age;
}
char *getName() {
return this->name;
}
void setAge(int age) {
this->age = age;
}
void setName(char *name) {
this->name = name;
}
};
int main() {
Student stu1("李鬼", 34);
Student stu2 = stu1;
cout << stu2.getName() << " , " << stu2.getAge() << endl;
cout << "main " << &stu1 << endl; // 地址的打印是一样的, 注意:cnetos的环境 地址打印有差异,要注意
// TODO 拷贝构造函数的注意点:
// Student stu1("李鬼", 34);
// Student stu2;
// stu2 = stu1; // 这样赋值是不会调用 自定义拷贝构造函数,但是会调用默认赋值
// Student stu2 = stu1; // 这样赋值是会调用 自定义拷贝构造函数,我们自己赋值
// cout << stu2.getName() << " , " << stu2.getAge() << endl;
getchar(); // 程序等待在这一行
return 0;
} // main函数弹,stu1栈成员会回收 stu2栈成员会回收
*/
// TODO 这种写法 拷贝构造函数 到底会不会调用
int main() {
Student *student1 = new Student("杜子腾", 39);
Student *student2 = student1; // 压根就不会执行拷贝构造函数(指针指向问题,和我们刚刚那个 对象2=对象1 是两回事) 如图2
student2->setAge(99);
cout << student1->getName() << student1->getAge() << endl; //99
return 0;
}
拷贝构造函数02.png
三、常量相关
#include <iostream>
#include <string.h>
#include <string.h>
using namespace std;
int main() {
// *strcpy (char *__restrict, const char *__restrict);
// strcpy()
int number = 9;
int number2 = 8;
// 常量指针
const int * numberP1 = &number;
// *numberP1 = 100; // 报错,不允许去修改【常量指针】存放地址所对应的值
// numberP1 = &number2; // OK,允许重新指向【常量指针】存放的地址
// 指针常量
int* const numberP2 = &number;
*numberP2 = 100; // OK,允许去修改【指针常量】存放地址所对应的值
// numberP2 = &number2; // 报错,不允许重新指向【指针常量】存放的地址
// 常量指针常量
const int * const numberP3 = &number;
// *numberP3 = 100; // 报错,不允许去修改【常量指针常量】存放地址所对应的值
// numberP3 = &number2; // 报错,不允许重新指向【常量指针常量】存放的地址
return 0;
}
四、static关键字
/**
* 静态的总结:
* 1.可以直接通过类名::静态成员(字段/函数)
* 2.静态的属性必须要初始化,然后再实现(规则)
* 3.静态的函数只能取操作静态的属性和方法(Java)
*/
#include <iostream>
using namespace std;
class Dog {
public:
char * info;
int age;
// 先声明
static int id;
static void update() {
id += 100;
// 报错:静态函数不能调用非静态函数(Java)
// update2();
}
void update2() {
id = 13;
}
};
// 再实现
int Dog::id = 9;
int main() {
Dog dog;
dog.update2(); // 普通函数
Dog::update(); // 静态函数
dog.update(); // 对象名.静态函数(一般都是使用::调用静态成员,这种方式可以 知道就行)
cout << Dog::id << endl;
return 0;
}
五、this
#include <iostream>
using namespace std;
class Worker {
// 默认的构造函数 栈区开辟空间 暴露 地址 == this指针
public:
char * name;
int age = NULL; // C++中不像Java,Java有默认值, 如果你不给默认值,那么就是系统值 -64664
// int * const 指针常量【地址对应的值能改,地址不可以修改】
// const int * 常量指针【地址可以修改,地址对应的值不能改】
// 纠结:原理:为什么可以修改age
// 默认持有隐式的this【类型 * const this】
void change1() {
// 代表指针地址不能被修改
// this = 0x6546; // 编译不通过,地址不能被修改,因为是指针常量
// 隐式的this
// 但是指针地址的值是可以修改的
// 地址对应的值能改
this->age = 100;
this->name = "JJJ";
}
// 默认现在:this 等价于 const Student * const 常量指针常量(地址不能改,地址对应的值不能改)
void changeAction() const {
// 地址不能改
// this = 0x43563;
// 地址对应的值不能改
// this->age = 100;
}
// 原理:修改隐士代码 const 类型 * const 常量指针常量
void showInfo() const {
// this->name = "";
// this->age = 88;
// 只读的
cout << "age:" << age << endl;
}
};
int main() {
return 0;
}
六、友元函数
#include <iostream>
using namespace std;
class Person {
private: // 私有的age,外界不能访问
int age = 0;
public:
Person(int age) {
this->age = age;
}
int getAge() {
return this->age;
}
// 定义友元函数 (声明,没有实现)
friend void updateAge(Person * person, int age);
};
// 友元函数的实现,可以访问所以私有成员
void updateAge(Person* person, int age) {
// 默认情况下:不能修改 私有的age
// 谁有这个权限:友元(拿到所有私有成员)
person->age = age;
}
int main() {
Person person = Person(9);
updateAge(&person, 88);
cout << person.getAge() << endl;
return 0;
}
七、友元类
// ImageView 私有成员 可以通过Class来访问,但是Class操作的native C++代码)
#include <iostream>
using namespace std;
class ImageView {
private:
int viewSize;
friend class Class; // 友元类
};
// Java每个类,都会有一个Class,此Class可以操作 ImageView私有成员
class Class {
public:
ImageView imageView;
void changeViewSize(int size) {
imageView.viewSize = size;
}
int getViewSize() {
return imageView.viewSize;
}
};
int main() {
Class mImageViewClass;
mImageViewClass.changeViewSize(600);
cout << mImageViewClass.getViewSize() << endl;
return 0;
}
八、总结
//Pig.h文件
#include <iostream>
using namespace std;
#ifndef PIG_H // 你有没有这个宏(Java 宏==常量)
#define PIG_H // 定义这个宏
class Pig {
private:
int age;
char * name;
public:
// 静态成员声明
static int id;
// 构造函数的声明系列
Pig();
Pig(char *);
Pig(char *,int);
// 析构函数
~Pig();
// 拷贝构造函数
Pig(const Pig & pig);
// 普通函数 set get
int getAge();
char * getName();
void setAge(int);
void setName(char *);
void showPigInfo() const; // 常量指针常量 只读
// 静态函数的声明
static void changeTag(int age);
// 友元函数的声明
friend void changeAge(Pig * pig, int age);
};
#endif // 关闭/结尾
//Pig.cpp
#include "Pig.h"
// TODO ========下面是 普普通通 常规操作 对象::
// 实现构造函数
Pig::Pig() {
cout << "默认构造函数" << endl;
}
Pig::Pig(char * name) {
cout << "1个参数构造函数" << endl;
}
Pig::Pig(char * name, int age) {
cout << "2个参数构造函数" << endl;
}
// 实现析构函数
Pig::~Pig() {
cout << "析构函数" << endl;
}
// 实现 拷贝构造函数
Pig::Pig(const Pig &pig) {
cout << "拷贝构造函数" << endl;
}
int Pig::getAge() {
return this->age;
}
char * Pig::getName() {
return this->name;
}
void Pig::setAge(int age) {
this->age = age;
}
void Pig::setName(char * name) {
this->name = name;
}
void Pig::showPigInfo() const {
} // 常量指针常量 只读
// TODO =================== 静态 和 友元 注意点 自己理解
// 实现 静态属性【不需要增加 static关键字】
int Pig::id = 878;
// 实现静态函数,【不需要增加 static关键字】
void Pig::changeTag(int age) {
}
// 友元的实现
// 友元特殊:不需要关键字,也不需要 对象:: ,只需要保证 函数名(参数)
void changeAge(Pig * pig, int age) {
}