C++学习笔记
文章目录
引用的使用
- 作为函数的参数,相当于地址传递
// 函数的引用作为参数
void swap(int &a, int &b) {
int temp;
temp = a;
a = b;
b = temp;
}
- 作为函数返回的左值
// 函数的返回值不能是局部变量的引用,在cloin中默认不能返回局部变量的引用
int &test() {
static int c;
c = 100;
return c;
}
int &i = test();
cout << i << endl;
// 函数作为变量的左值
test() = 1000;
cout << i << endl;
- 注意以引用作为返回值的函数,不能返回局部变量的引用,原因,在函数体内部,创建的变量是在栈区生成,当函数执行完毕后,将会销毁
- 引用常量:const int &b 定义的变量,不能够改变b指向的值
int test1(const int &b) {
int c = 1 + b;
return c;
}
类的定义
- 通过点与圆的圆心的距离案例
- 定义点类
Point.h
#include <iostream>
using namespace std;
#include <string>
class Point {
public:
int getX() const;
void setX(int x);
int getY() const;
void setY(int y);
Point();
Point(int x, int y);
Point(const Point &point);
virtual ~Point();
private:
int x;
int y;
};
Point.cpp
#include "Point.h"
int Point::getX() const {
return x;
}
void Point::setX(int x) {
Point::x = x;
}
int Point::getY() const {
return y;
}
void Point::setY(int y) {
Point::y = y;
}
Point::Point() {}
Point::Point(int x, int y) {
cout<<"Point的有参构造函数执行"<<endl;
Point::x = x;
Point::y = y;
}
Point::Point(const Point &point) {
cout<<"Point的拷贝构造函数执行"<<endl;
Point::x = point.getX();
Point::y = point.getY();
}
Point::~Point() {
cout << "Point析构函数执行"<<endl;
}
- 拷贝构造函数的定义(定义引用常量)
Point::Point(const Point &point) {
cout<<"Point的拷贝构造函数执行"<<endl;
Point::x = point.getX();
Point::y = point.getY();
}
Circle.h的定义
#include "Point.h"
#include <iostream>
using namespace std;
#include <string>
class Circle {
public:
Circle(const Point &point, int r);
Circle();
Point getPoint() const;
void setPoint(const Point &point);
int getR() const;
void setR(int r);
virtual ~Circle();
private:
Point point;
int r;
};
#endif //C__DOMO_CIRCLE_H
Circle.cpp的定义
//
// Created by Lenovo on 2022/11/4.
//
#include "Circle.h"
Point Circle::getPoint() const {
return point;
}
Circle::Circle(const Point &point, int r) : point(point), r(r) {
cout<<"Circle的有参构造函数执行"<<endl;
}
Circle::Circle() {}
Circle::~Circle() {
cout << "Circle的析构函数执行" << endl;
}
void Circle::setPoint(const Point &point) {
Circle::point = point;
}
int Circle::getR() const {
return r;
}
void Circle::setR(int r) {
Circle::r = r;
}
主函数的编写,main.cpp
#include <iostream>
#include "Point.h"
#include "Circle.h"
using namespace std;
int pow(int a){
return a*a;
}
bool isCircleInclude(Circle& circle,Point& point){
int j=pow(circle.getPoint().getX()-point.getX())+pow(circle.getPoint().getY()-point.getY());
return pow(circle.getR())<=j? true: false;
}
int main(){
Point point(10,20);
Circle circle(point,20);
Point test(10,20);
Point newtest(test);
cout<<newtest.getY()<<" "<<newtest.getX()<<endl;
bool b = isCircleInclude(circle, test);
// cout<<bool (b)<<endl;
return 0;
}
类的对象对象特性
构造函数的调用规则
- 在C++类当中,会默认提供无参构造函数,拷贝构造函数,与析构函数
- 如果提供了有参构造函数,则不会提供无参构造函数,但会提供拷贝构造函数
- 如果提供了拷贝构造函数,则不会提供无参构造函数
- 深拷贝与浅拷贝
- 对于在类对象内部有指针属性的类,在拷贝构造函数中要采用深拷贝的方式,即在堆区重新申请一片内存空间
Person(const Person &p){
this->age=p.age;
this->height=new int(*p.height);
}
- 在析构函数中需要手动将值指针对象删除
~Person() {
if(this->height!= NULL){
delete this->height;
// 避免出现野指针的情况
this->height=NULL;
}
}
初始化列表
Person(int age, int height):age(age),height(new int (height)) {
// this->age=age;
// this->height=new int(height);
}
Person(const Person &p):age(p.age),height(new int (*p.height)){
// this->age=p.age;
// this->height=new int(*p.height);
}
静态成员变量与静态方法
- 在编译时分配内存
- 在类中定义,类外赋值
- 共享同一个变量
- 通过对象.变量名 或者类名::变量名 的方法访问静态成员变量
class Person{
static string address;
};
string Person::address="晋中市";
cout<<p.address;
cout<<Person::address;
- 静态方法中只能访问静态成员变量
static void func(){
cout<<"静态成员方法"<<endl;
cout<<"地址是"<<Person::address;
}
- 可通过两种方式调用静态方法
p.func();
Person::func();
在c++中类的成员变量与成员方法是分开存储的,空对象默认是占据一个字节的空间
this指针
- this是指向该对象的指针,*this代表的就是该对象
- this可以解决命名冲突的问题
- this指针可以解决成员函数需要返回本对象的指针的问题(链式编程)
// 实现两者年龄的相加
Person& addage(Person& p){
this->age+=p.age;
return *this;
}
int age;
int *height;
static string address;
};
int main() {
Person p1(10,20);
Person p2(p1);
p2.addage(p1).addage(p1).addage(p1);
cout<<p2.age<<endl;
return 0;
注意:为什么addage函数的返回值需要加&?
理由:如果不加&,代表该函数返回的是一个新的对象,而不是原先的对象,添加了&符号,相当于给原有的对象,添加了别名,在使用链式编程时,可以一值对原对象进行操作
常对象与常函数
void test01() const{
this->age=10;
cout<<"常函数";
}
mutable int age;
- 在常函数中不能修改成员变量的值,但是如果成员变量添加了mutable 关键字,在常函数中可以修改,这个变量叫做常变量
友元
全局函数做友元
friend void test01();
类做友元
// 类做友元
friend class GoodGay;
成员函数做友元(在colin中暂未跑通)
// 成员函数做友元
friend void GoodGay::void ();
继承
继承的基本语法
class html{
public:
void header(){
cout<<"头部页面"<<endl;
}
void foot(){
cout<<"尾部页面"<<endl;
}
void Fenlei(){
cout<<"java---python---前端---云计算"<<endl;
}
};
class Java: public html{
public:
void content(){
cout<<"java页面"<<endl;
}
};
class Python: public html{
public:
void content(){
cout<<"python页面"<<endl;
}
};
int main() {
Java java;
java.header();
java.Fenlei();
java.content();
java.foot();
cout<<"-----------"<<endl;
Python python;
python.header();
python.Fenlei();
python.content();
python.foot();
return 0;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
继承方式
- public继承:
- 父类中的public权限在子类中是public
- 父类中的protect权限在子类中是protect
- 父类中的private权限在子类中无法访问
- protect继承
- 父类中的protect权限与public权限,在子类中可以访问,但在子类中变为保护权限,类外无法访问
- 父类中的的private权限子类中无法访问
- private继承
- 父类中的protect权限与public权限,在子类中可以访问,但在子类中变为私有权限,外部无法访问
继承的对象模型
- 对于父类中的私有属性,子类也会继承,只不过被编译器隐藏了
class Base{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class SonPublic: public Base{
public:
void func(){
this->m_A;//在父类中的公共权限,在之类中扔然是
this->m_B;//保护权限可以访问
// this->m_C;//私有权限无法访问
}
private:
int m_D;
};
int main() {
SonPublic sonPublic;
cout<<"class size is "<<sizeof (sonPublic)<<endl;
return 0;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
- 运行结果
继承中构造函数与析构函数的执行顺序
- 结论:先执行父类的构造函数,在执行子类的构造函数,析构函数的执行顺序相反
class Base {
public:
Base() {
cout << "base 的无参构造函数执行" << endl;
}
Base(int mA, int mB, int mC) : m_A(mA), m_B(mB), m_C(mC) {
cout << "base 的有参构造函数执行" << endl;
}
virtual ~Base() {
cout << "base 的析构函数执行" << endl;
}
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
// 公共继承
class SonPublic : public Base {
public:
SonPublic() {
cout << "SonPublic的无参构造函数" << endl;
}
SonPublic(int mA, int mB, int mC, int mD) : Base(mA, mB, mC), m_D(mD) {}
void func() {
this->m_A;//在父类中的公共权限,在之类中扔然是
this->m_B;//保护权限可以访问
// this->m_C;//私有权限无法访问
}
virtual ~SonPublic() {
cout << "SonPublic的析构函数" << endl;
}
private:
int m_D;
};
int main() {
SonPublic sonPublic;
// cout << "class size is " << sizeof(sonPublic) << endl;
return 0;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
运行结果
继承中的同名处理
class Base {
public:
Base() {
// cout << "base 的无参构造函数执行" << endl;
}
Base(int mA, int mB, int mC) : m_A(mA), m_B(mB), m_C(mC) {
// cout << "base 的有参构造函数执行" << endl;
}
void func() {
cout << "父类中的func" << endl;
}
virtual ~Base() {
// cout << "base 的析构函数执行" << endl;
}
void func(int x){
cout<<"父类中的有参func"<<endl;
}
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
// 公共继承
class SonPublic : public Base {
public:
SonPublic() {
// cout << "SonPublic的无参构造函数" << endl;
}
SonPublic(int mA, int mB, int mC, int mD) : Base(mA, mB, mC), m_A(mD) {}
void func() {
cout << "子类中的func" << endl;
}
virtual ~SonPublic() {
// cout << "SonPublic的析构函数" << endl;
}
public:
int m_A;
};
int main() {
SonPublic sonPublic(10, 20, 30, 40);
cout << "子类中的" << sonPublic.m_A << endl;
cout << "父类中的" << sonPublic.Base::m_A << endl;
sonPublic.func();
sonPublic.Base::func();
sonPublic.Base::func(10);
// cout << "class size is " << sizeof(sonPublic) << endl;
return 0;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
- 运行结果
同名静态成员处理
菱形继承问题
class Aninmel{
public:
int age;
};
class Sheep: virtual public Aninmel{
};
class Tuo: virtual public Aninmel{
};
class SheepTuo: public Sheep, public Tuo{
};
int main() {
SheepTuo sheepTuo;
sheepTuo.Sheep::age=20;
sheepTuo.Tuo::age=30;
cout<<"sheepTuo.Sheep::age "<<sheepTuo.Sheep::age<<endl;
cout<<" sheepTuo.Tuo::age "<< sheepTuo.Tuo::age<<endl;
cout<<" sheepTuo.age"<<sheepTuo.age<< endl;
Sheep sheep;
sheep.age=10;
cout<<"sheep.age "<<sheep.age<<endl;
// SonPublic sonPublic(10, 20, 30, 40);
// cout << "子类中的" << sonPublic.m_A << endl;
// cout << "父类中的" << sonPublic.Base::m_A << endl;
// sonPublic.func();
// sonPublic.Base::func();
// sonPublic.Base::func(10);
// cout << "class size is " << sizeof(sonPublic) << endl;
return 0;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
运行结果
多态
多态的基本语法
- 地址早绑定,在编译阶段就进行绑定,
class Animel{
public:
void speak(){
cout<<"动物在说话"<<endl;
}
};
class Cat:public Animel{
public:
void speak(){
cout<<"小猫在说话"<<endl;
}
};
void test01(Animel& animel){
animel.speak();
}
int main() {
Cat cat;
test01(cat);
// std::cout << "Hello, World!" << std::endl;
return 0;
}
- 地址晚绑定,在运行阶段进行地址的绑定,将父类中的方法添加virtual关键字,变为虚函数
class Animel{
public:
virtual void speak(){
cout<<"动物在说话"<<endl;
}
};
多态原理
多态案例——计算器类
class AbstractCalute {
public:
virtual int getresult() {
return 0;
}
int num1;
int num2;
};
class AddCalculate : public AbstractCalute {
int getresult() {
return num1 + num2;
}
};
class SpCalculate : public AbstractCalute {
int getresult() {
return num1 - num2;
}
};
class MulCalculate : public AbstractCalute {
int getresult() {
return num1 * num2;
}
};
class ChuCalculate : public AbstractCalute {
int getresult() {
return num1 / num2;
}
};
void test02() {
AbstractCalute *pCalute = new AddCalculate;
pCalute->num1 = 10;
pCalute->num2 = 20;
cout << "加法结果是" << pCalute->getresult() << endl;
delete pCalute;
pCalute = new SpCalculate;
pCalute->num2 = 20;
pCalute->num1 = 20;
cout << "减法结果是" << pCalute->getresult() << endl;
}
int main() {
test02();
// std::cout << "Hello, World!" << std::endl;
return 0;
}
注意: 在开发中遵循开闭原则,即对扩展开放,对修改关闭
纯虚函数与抽象类
class AbstractCalute {
public:
virtual int getresult() =0;
int num1;
int num2;
};
多态案例二——饮品制作
class AbatractDrink {
public:
// 注水
void Bool() {
cout << "倒水";
};
// 方材料
virtual void PutThing() = 0;
// 泡
virtual void Pao() = 0;
// 倒出饮料
virtual void Dao() = 0;
void makedrink() {
this->Bool();
this->PutThing();
this->Pao();
this->Dao();
}
};
class Tea : public AbatractDrink {
void PutThing() override {
cout << "放入茶叶" << endl;
}
void Pao() override {
cout << "泡茶" << endl;
}
void Dao() override {
cout << "倒茶" << endl;
}
};
void Drink(AbatractDrink *abatractDrink) {
abatractDrink->makedrink();
}
void test03(){
Drink(new Tea);
}
int main() {
test03();
// std::cout << "Hello, World!" << std::endl;
return 0;
}
虚析构函数与纯虚析构函数
class AbstractAnimel {
public:
virtual void speak() = 0;
virtual ~AbstractAnimel() = 0;
AbstractAnimel(string *age);
AbstractAnimel();
string *age;
};
AbstractAnimel::~AbstractAnimel() {
if (this->age== nullptr){
delete this->age;
this->age= nullptr;
}
}
AbstractAnimel::AbstractAnimel(string *age) : age(age) {}
AbstractAnimel::AbstractAnimel() {}
class Cat : public AbstractAnimel {
public:
Cat(string *name) : name(name) {}
Cat(string *age, string *name) : AbstractAnimel(age), name(name) {}
virtual ~Cat() {
if (this->name != nullptr) {
delete this->name;
this->name = nullptr;
}
}
public:
void speak() override {
cout << *this->age<<" "<<*this->name<<" " <<"猫在叫" << endl;
}
string *name;
};
void test04() {
AbstractAnimel *pCat = new Cat(new string("Animel"),new string("Cat"));
pCat->speak();
delete pCat;
}
int main() {
test04();
// std::cout << "Hello, World!" << std::endl;
return 0;
}
多态案例——电脑组装
// cpu
class Cpu {
public:
virtual void calculate() = 0;
};
// 存储器
class Memory {
public:
virtual void Storg() = 0;
};
// 显卡
class VideoCard {
public:
virtual void Show() = 0;
};
class InetelCpu : public Cpu {
public:
void calculate() override {
cout << "Intel Cpu运行" << endl;
}
};
class LevonMemory : public Memory {
public:
void Storg() override {
cout << "联想存储器正在运行" << endl;
}
};
class LevonVideoCard : public VideoCard {
public:
void Show() override {
cout << "显卡正在运行" << endl;
}
};
class Cpumpter {
public:
Cpumpter(Cpu *cpu, Memory *memory, VideoCard *videoCard) : cpu(cpu), memory(memory), videoCard(videoCard) {
}
virtual ~Cpumpter();
void MakeCumpter() {
this->cpu->calculate();
this->memory->Storg();
this->videoCard->Show();
}
Cpu *cpu;
Memory *memory;
VideoCard *videoCard;
};
Cpumpter::~Cpumpter() {
if (this->cpu != nullptr) {
delete this->cpu;
this->cpu = nullptr;
}
if (this->memory != nullptr) {
delete this->memory;
this->memory = nullptr;
}
if (this->videoCard != nullptr) {
delete this->videoCard;
this->videoCard = nullptr;
}
}
class LevonCpuptor : public Cpumpter {
public:
LevonCpuptor(Cpu *cpu, Memory *memory, VideoCard *videoCard, const string &name) : Cpumpter(cpu, memory, videoCard),
name(name) {
}
virtual ~LevonCpuptor() {
}
string name;//电脑名称
};
int main() {
Cpu *pCpu = new InetelCpu;
Memory *memory=new LevonMemory;
VideoCard *videoCard=new LevonVideoCard;
Cpumpter *cpumpter=new LevonCpuptor(pCpu,memory,videoCard,"联想电脑");
cpumpter->MakeCumpter();
delete cpumpter;
// std::cout << "Hello, World!" << std::endl;
return 0;
}
二进制文件——写文件
void test01() {
// 创建写文件的流
ofstream ofs;
ofs.open("test.txt", ios::app);
ofs << "张三" << endl;
ofs << "20" << endl;
ofs.close();
}
二进制文件——读文件
void test05() {
Person person(12, "name");
ofstream ofs("test.txt", ios::binary | ios::out);
ofs.write((const char *) &person, sizeof(Person));
ofs.write((const char *) &person, sizeof(Person));
ofs.write((const char *) &person, sizeof(Person));
ofs.write((const char *) &person, sizeof(Person));
ofs.close();
ifstream ifs("test.txt", ios::binary | ios::in);
if (!ifs.is_open()) {
cout << "文件打开失败" << endl;
return;
}
Person temp[5];
ifs.read((char *) &temp, sizeof(temp));
// cout<<temp.name<<" "<<temp.age<<endl;
for (int i = 0; i < 5; ++i) {
Person temp1 = temp[i];
cout << temp1.name << " " << temp1.age << endl;
}
ifs.close();
}