栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++学习笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++学习笔记

黑马C++:https://www.bilibili.com/video/BV1et411b73Z?p=1&vd_source=feb3308f828cbba5d73ba04cf01b1e8a

C++学习笔记
  • const修饰指针
  • 引用
  • 函数重载
  • main:处理命令行选项
  • 封装、继承、多态
    • 构造函数、析构函数
    • 静态成员
    • const 修饰成员函数
    • 友元 friend
    • 继承
    • 多态
      • 纯虚函数
      • 虚析构和纯虚析构


const修饰指针
int a = 10, b = 20;
const int* p1 = &a;	//常量指针,const修饰*p1,即指针p1指向的值不可修改,常量指针指向的值是个常量
int* const p2 = &b;	//指针常量,const修饰p2,即指针p2本身不可修改,指针常量的指向不可以修改

引用
int a = 10 , c = 20;
int& b = a;	//引用就是给变量取别名

//引用一旦确定就不可以更改,只能一直是a的别名,但是值可以修改,修改b的值就相当于修改a的值
&b = &c; //错误
b = c;	 //正确,将c的值赋给b,此时a的值也是20
//引用本质上就是一个指针常量,指向的地址不可以发生改变,但是该地址存放的值可以改变
int* const b = &a;

//常量引用作为形参,防止变量被修改
int test1(const int& a);

//不要返回局部变量的引用
int& test2()
{
	int a = 10;//错误
	//static int a = 10;//正确
	return a;
}

test2() = 20;//函数的返回值是引用时,可以作为左值

函数重载
  • 同一作用域下
  • 函数名称相同
  • 参数不同(参数类型、数量、顺序)
  • 函数的返回值不可以作为函数重载的条件

main:处理命令行选项
// argc表示数组中字符串的数量;argv是一个数组,它的元素是指向C风格字符串的指针,其中第一个元素指向程序的名字,最后一个指针之后的元素保证为0
// 假设现在的可执行文件名为prog,运行时需要传递 -d -o ofile data0 四个参数,即:prog -d -o ofile data0
// 此时 argc = 5;
//	argv[0] = "prog";
//	argv[1] = "-d";
//  argv[2] = "-o";
//	argv[3] = "ofile";
//	argv[4] = "data0"
//	argv[5] = 0; 
int main(int argc, char *argv[]) {...}
// 或者
int main(int argc, char **argv) {...}

封装、继承、多态 构造函数、析构函数
class Person
{
public:
	Person(){}					//无参构造
	Person(int a){}				//有参构造
	Person(const Person &p){}	//拷贝构造

	~Person(){}					//析构函数
};

//显示调用
Person p1;					//无参
Person p2 = Person(10);		//有参
Person p3 = Person(p2);		//拷贝
Person(10);					//匿名对象,当前行执行结束立即释放

//隐式转换法
Person p4 = 10;//相当于 Person p4 = Person(10);
Person p5 = p4;//拷贝构造
  • 拷贝构造函数的调用时机
class Person
{
pubilc:
	Person(){}
	Person(int age){}
	Person(const Person &p){}

	~Person(){}
int m_Age;
};

//使用一个已经创建完毕的对象来初始化一个新对象
void test1()
{
	Person p1(20);
	Person p2(p1);
}
//以值传递的方式给函数参数传值
void dowork(Person p){}
void test2()
{
	Person p ;
	dowork(p);
}
//值方式返回局部对象
Person dowrk2(){
	Person p1;
	return p1;
}

void test3()
{
	Person p = dowrk2();
}
  • 默认情况下,C++编译器至少给一个类添加3个函数:
    1、默认构造函数(无参,函数体为空)
    2、默认析构函数(无参,函数体为空)
    3、默认拷贝构造函数,对属性进行值拷贝
  • 构造函数调用规则如下:
    1、如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造
    2、如果用户定义拷贝构造函数,C++不会提供其他构造函数
  • 当其他类对象作为本类成员:构造的时候先构造类对象(其他类),再构造自身;析构的时候先析构自身,在析构类对象
  • 创建子类对象时,先构造父类,后构造子类本身;释放子类对象时,先析构子类本身,再析构父类
    先有父亲再有儿子,析构相反
静态成员
  • 静态成员变量
    1、所有对象共享同一份数据
    2、在编译阶段分配内存
    3、类内声明,类外初始化
  • 静态成员函数
    1、所有对象共享同一个函数
    2、静态成员函数只能访问静态成员变量
  • 不能通过类名来调用类的非静态成员函数
  • 类的对象可以使用静态成员函数和非静态成员函数
  • 静态成员函数中不能引用非静态成员
  • 类的非静态成员函数可以调用静态成员函数,反之不能
  • 类的静态成员变量必须先初始化再使用
    总结:
    1、静态方法能不能引用非静态资源?不能,实例化对象的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。
    2、静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。
    3、非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是实例化对象之后才产生的,那么属于类的内容它都认识。
const 修饰成员函数
  • 常函数
    1、成员函数后加const称之为常函数
    2、常函数不可以修改成员属性
    3、成员属性声明时加关键字mutable后,在常函数中依然可以修改
  • 常对象
    1、声明对象前加const称之为常对象
    2、常对象只能调用常函数
友元 friend
  • 全局函数做友元:在类中声明一个友元全局函数,则该全局函数可以访问类中的私有成员 friend void GlobalFunc();
  • 类做友元:在类A中声明类B为友元类,则类B的对象就可以访问类A中的私有成员 friend class B;
  • 成员函数做友元:在类A中声明类B的某个成员函数为友元成员函数,则类B中的该成员函数可以访问类A中的私有成员 firend void B::Func();
继承
类型访问权限
public类内类外均可以访问
protected类内可以访问,类外不可以访问,但子类可以访问
private类内可以访问,类外不可以访问,子类不可以访问

struct 默认为公有成员,class默认为私有成员

继承方式继承属性变化
public继承父类公有为公有,继承父类保护为保护;不可访问父类私有
protect继承父类公有和保护为保护;不可访问父类私有
private继承父类公有和保护为私有;不可访问父类私有

不管何种继承方式,父类的私有都不可访问,但是父类中的所有非静态成员属性都会被子类继承(包括私有);想要访问父类的私有可以通过友元的方式

  • 继承时子类与父类有相同名称的成员(变量或函数)时,子类的直接访问,父类的需要加上父类的作用域
  • 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏父类的所有同名成员函数(比如函数重载时)
多态
  • 静态多态:函数重载和运算符重载属于静态多态,复用函数名;静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态:派生类和虚函数实现运行时多态;动态多态的函数地址晚绑定 - 运行阶段确定函数地址;动态多态通过父类的指针或引用执行子类对象
  • 虚函数表指针:指向虚函数表,表内存放的是虚函数的地址;当一个子类继承这个类之后,虚函数表指针同样也会被继承下来,只不过继承下来的虚函数表指针指向的仍然是父类的虚函数地址;当在子类重写了虚函数之后,子类的虚函数表内部会被替换成子类的虚函数地址;当父类的指针或者引用指向子类对象的时候,就会发生多态
纯虚函数
virtual 返回值类型 函数名 (参数列表) = 0;

1、当类中只要有了一个纯虚函数,这个类称为抽象类;
2、抽象类无法实例化对象;
3、子类必须重写抽象类中的纯虚函数,否则也属于抽象类

虚析构和纯虚析构
  • 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
  • 解决方式:将父类中的析构函数改为虚析构或者纯虚析构
  • 虚析构和纯虚析构:
    1、可以解决父类指针释放子类对象
    2、都需要具体的函数实现
    3、如果是纯虚析构,该类属于抽象类,无法实例化对象
    4、虚析构和纯虚析构两者只能有一个
    5、纯虚析构函数需要有声明也要有实现,在类外实现
virtual ~类名(){}		//虚析构
virtual ~类名() = 0;		//纯虚析构

总结:
1、虚析构或纯虚析构就是用来通过父类指针释放子类对象
2、如果子类中没有堆区数据,可以不写虚析构或纯虚析构
3、拥有纯虚析构函数的类也属于抽象类

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1011646.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号