c++笔记

开始
1
C语言中三目运算符不可以当左值;即其返回值为一个值;
c++中三目运算返回的可以是变量a并且变量a可以再次赋值;

关于const
C语言与C++的不同

在这里插入图片描述

在C语言中const int a;a的值扔可以通过指针修改其值属于变量,
而在c++中const int a=10;中a不能通过指针修改;a相当于宏定义为10但是其作用域不同define可以在定以之后使用,而const只在其函数内;

在这里插入图片描述

C++中如果用指针指向一个常量会临时开辟一个空间;

枚举类型
C语言与c++不同
在C语言中枚举时第一个变量位置为0;可以使用其位置找到该枚举;
而c++中只能使用其枚举的名称;

c++引用的注意
例如int &b=a;相当于b是a的别名 引用规则如图;

在这里插入图片描述
在这里插入图片描述

指针的引用
二级指针简单了解。。

在这里插入图片描述

内联函数
Inline +函数类型 +函数名;
该类型适用于函数体比较小且调用次数较多的函数
假如函数体较大定义为inline后他也不会按inline方式去进行

占位符:
在函数参数中只放参数类型不放参数变量,称为亚元。该用处可以在调用函数时体现
可以用占位符的方式调用参数数量不同的函数。
函数指针;
即定义一个指针去接收函数的地址。

类与对象的学习
类中存在public;peotected;private;
public为公开类型,在类内类外都可访问;
Protected和private访问权限都相同,即只能在类内访问,但是protected与private不同的是在继承时,派生类的继承方式不同。

结构体作为参数的三种方法

在这里插入图片描述

小细节

不规范写法
在这里插入图片描述

规范写法
在这里插入图片描述

在类的封装过程中不能直接在设置成原时给与其计算过程,
错误写法:

程序运行时会给该类分配空间,该空间内各个成员获得空间,操作可能是初始化大概,具体不知道是为啥。
在这里插入图片描述

析构函数:
在一个对象被销毁之前会调用析构函数,该函数的作用是用来释放自己所使用对象申请
析构函数调用规则是先调用的函数后析构,最后调用的对象先析构;

Const 与static的区别与总结

在这里插入图片描述

在这里插入图片描述

Static 定义static变量时如果不给其初始化其默认值为0或者为‘0’,

另外static类型变量只能被赋值一次
另外static修饰的变量只在其作用域之内起作用
如果类中的成员为static类型其初始化必须在类外。
初始化格式 成员类型:类名::静态成员变量名
在main函数中可以直接访问不用对象调用 类名::成员名
如果要返回一个静态成员变量必须用一个静态函数来返回。
下面为例子配合理解

在这里插入图片描述

假如用static修饰一个函数时,该函数只能在本程序文件中调用

友元知识

友元函数
在类中给一个类外函数权限访问类中成员
格式 (friend 函数声明)

友元类、
可以在一个类中直接设置另一个类为友元类,并且友元类只能单向性访问
在这里插入图片描述

类与类之间的关系

继承类的规则
格式 派生类名:public 基类名

另外派生类的空间大小大于等于基类;

函数的重载 覆盖 隐藏 的区别

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

回头再看C++多态的理解

多态即为统一指令下的对象的行为不同。

回头又看了一下C++的多态概念 之前学习的时候没理解

大概是在C++过程中你使用父类指针和子类指针调用一个函数时其调用的函数是不相同的。
下面我通过一段代码加强记忆

                      
#include <iostream>
#include <string>
using namespace std;

class Yuebuqun
{
public:
	Yuebuqun( string kongfu)
	{
		this->kongfu = kongfu;
	}
	virtual void fight()//这里是关键定义fight函数为虚函数在子类函数重写该函数在不同指针调用时体现的功能不同,这就是简单的体现了多态。
	{
		cout << "岳不群" << "使出了" << kongfu << "打人" << endl;
	}
private:
	string kongfu;
};
class Linpingzhi:public Yuebuqun
{
public:
		Linpingzhi(string kongfu):Yuebuqun(kongfu){}
		void fight()
		{
			cout << "林平之" << "使用了" << kongfu << "打人" << endl;
		}
private:
	string kongfu;
};
int main()
{
	Yuebuqun* xiaoyy = new  Yuebuqun("葵花宝典");
	xiaoyy->fight();
	
	Linpingzhi* xiaopp = new  Linpingzhi("僻邪剑谱");
	xiaopp->fight();
	delete xiaopp;delete xiaoyy;
}


另外此定义为虚函数与虚继承没关系,不要误解。今天看到一篇关于虚继承的好文章直接搬过来吧

1.Cpp中的虚继承与虚基类

在多继承时,很容易产生命名冲突的问题,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示:


菱形继承

类A派生出类B和类C,类D继承自类B和类C,这个时候类A中的成员变量和成员函数继承到类D中变成了两份,一份来自A–>B–>D这条路径,另一份来自A–>C–>D这条路径。在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类A有一个成员变量a,那么在类D中直接访问a 就会产生歧义,编译器不知道它究竟来自A -->B–>D这条路径,还是来自A–>C–>D这条路径。下面是菱形继承的具体实现:
#include “iostream”

using namespace std;

// 间接基类
class A
{
protected:
    int m_a;
};
// 直接基类B
class B : public A
{
protected:
    int m_b;
};

// 直接基类C
class C : public A
{
protected:
    int m_c;
};

// 派生类D
class D : public B, public C
{
public:
    // void seta(int a) { m_a = a; }   命名冲突,为了解决命名冲突,可以使用void B::seta(int a){m_a = a;}
    void setb(int b) { m_b = b; }
    void setc(int c) { m_c = c; }

private:
    int m_d;
};

int main()
{
    D d;
    return 0;
}


2.虚继承
为了解决多继承时的命名冲突和冗余数据问题,C++提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上virtual关键字就是虚继承,请看下面的例子:
#include “iostream”

using namespace std;

// 间接基类
class A
{
protected:
    int m_a;
};
// 直接基类B
class B : virtual public A   // 加上关键字virtual!
{
protected:
    int m_b;
};

// 直接基类C
class C : virtual public A
{
protected:
    int m_c;
};

// 派生类D
class D : public B, public C
{
public:
    void seta(int a) { m_a = a; }   // 正确!
    void setb(int b) { m_b = b; }
    void setc(int c) { m_c = c; }

private:
    int m_d;
};

int main()
{
    D d;
    return 0;
}



虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的A就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。重新梳理一下本例的继承关系,如下图所示:


虚基类.jpg

观察这个新的继承体系,我们会发现虚继承的一个不太直观的特征:必须在虚派生的真实需求出现前就已经完成虚派生的操作。在上图中,当定义D类时才出现了对虚派生的需求,但是如果B类和C类不是从A类虚派生得到的,那么D类还是会保留A类的两份成员。换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。
3.虚基类成员的可见性
因为在虚继承的最终派生类中只保留了一份虚基类的成员,所以该成员可以被直接访问,不会产生二义性。此外,如果虚基类的成员只被一条派生路径覆盖,那么仍然可以直接访问这个被覆盖的成员。但是如果该成员被两条或多条路径覆盖了,那就不能直接访问了,此时必须指明该成员属于哪个类。
以图2中的菱形继承为例,假设在A中定义了一个名为x的成员变量,当我们在D中直接访问x时,会有三种可能性:
o如果B和C中都没有x的定义,那么x将被解析为B的成员,此时不存在二义性。
o如果B或C其中的一个类定义了x,也不会有二义性,派生类的x比虚基类的x优先级更高。
o如果B和C中都定义了x,那么直接访问x将产生二义性问题。
4.虚继承时的构造函数
在虚继承中,虚基类是由最终的派生类初始化的。换句话说,最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。
// 虚基类AA
class AA{
protected:
int m_a;
public:
AA(int a);
};
// 类外定义虚基类AA的构造函数
AA::AA(int a):m_a(a){}
// 直接派生类BB
class BB: virtual public AA{
protected:
int m_b;
public:
BB(int a, int b);
void show();
};
BB::BB(int a, int b): AA(a), m_b(b){}
void BB::show(){
cout << "m_a = " << m_a << ",m_b = " << m_b << endl;
}

// 直接派生类CC
class CC: virtual public AA{
public:
    CC(int a, int c);
    void show();
protected:
    int m_c;
};
CC::CC(int a, int c):AA(a), m_c(c){}
void CC::show(){
cout << "m_a = " << m_a << ",m_c = " << m_c << endl;
}

// 间接派生类DD
class DD: public BB, public CC{
protected:
    int m_d;
public:
    DD(int a, int b, int c, int d);
    void show();
};
DD::DD(int a, int b, int c, int d):AA(a), BB(90, b), CC(100, c), m_d(d){}
void DD::show(){
cout <<"m_a = " << m_a << ",m_b = " << m_b << ",m_c = " << m_c << ",m_d = " << m_d << endl;
}

int main()
{
    BB bb(10, 20);
    bb.show();
    CC cc(30, 40);
    cc.show();
    DD dd(50, 60, 70, 80);
    dd.show();
    return 0;
}


在最终派生类DD的构造函数中,除了调用BB和CC的构造函数,还调用了AA的构造函数,这说明DD不但要负责初始化直接基类BB和CC,还要负责初始化间接基类AA。而在以往的普通继承中,派生类的构造函数只负责初始化它的直接基类,再由直接基类的构造函数初始化间接基类,用户尝试调用间接基类的构造函数将导致错误。
现在采用了虚继承,虚基类AA在最终派生类DD中只保留了一份成员变量m_a,如果由BB和CC初始化m_a,那么BB和CC在调用AA的构造函数时很有可能给出不同的实参,这个时候编译器就会犯迷糊,不知道使用哪个实参初始化m_a。为了避免出现这种矛盾的情况,C++干脆规定必须由最终的派生类DD来初始化虚基类AA,直接派生类BB和CC对AA的构造函数的调用是无效的。在代码中,调用BB的构造函数时试图将m_a初始化为90,调用CC的构造函数时试图将m_a初始化为100,但是输出结果有力地证明了这些都是无效的,m_a最终被初始化为50,这正是在DD中直接调用AA的构造函数的结果。
另外,需要关注的是构造函数的执行顺序。虚继承时构造函数的执行顺序与普通继承时不同:在最终派生类的构造函数调用列表中,不管各个构造函数出现的顺序如何,编译器总是先调用虚基类的构造函数,再按照出现的顺序调用其他的构造函数;而对于普通继承,就是按照构造函数出现的顺序依次调用的

作者:CurryCoder
链接:https://www.jianshu.com/p/5bf9d99df2b5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二叉树的遍历

先序遍历
先根后左再右
中序遍历
先左后根再右
后序遍历
先左后右再根

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值