TouchGFX界面开发 | C++基础-程序员宅基地

技术标签: c++  # TouchGFX  开发语言  

C++基础

TouchGFX是一个基于STM32硬件,由C++写成的软件框架,所以有必要对C++基础有一定的了解

一、C++新特性

C 语言里,变量初始化必须在程序的前面, 而 C++ 则可以随用随定义。 C++ 也可以直接初始化,比如 int x(100); 这样就直接赋值 x=100

C++的输入输出方式:以 cincout 代替了C 语言里的 scanf 和 printf

  • cout 语法形式:
cout << x << endl;
// x 可以是任意数据类型(或表达式)
// endl 是换行符,与C里的"\n"效果一样
cout << x << y << endl;		//多个变量的输出
  • cin 语法形式:
cin >> x;		//x可以是任意数据类型
cin >> x >> y;	//多个变量的输入

C++的命名空间 namespace:using namespace std;

#include <iostream>
using namespace std;
int main(){
    
	cout << "Hello, World!" << endl;
	return 0;
}

注意上面程序中,头文件要写成 iostream,因为是标准输入输出流;带".h"的是非标准输入输出流。using 是编译指令, 声明当前命名空间的关键词,可以理解成使用命名空间 std,因为 cin 和 cout 都是属于 std 命名空间的,所以使用时必须加上 using namespace std;;cin 和 cout 也可以写成 std::cinstd::cout,其中 :: 表示作用域

为什么要使用命名空间呢 ? 有些名字容易冲突,所以会使用命名空间的方式进行区分,具体来说就是加个前缀。比如C++ 标准库里面定义了 vector 容器, 自己又写了个 vector 类,这时名字就冲突了。于是使用标准库里的名字时,都要加上 std:: 的前缀,即 std::vector 来引用。经常写全名比较繁琐,所以在名字没有冲突的情况下可以添加using namespace std;,那么接下去使用标准库里的名字时就可以不用再写std:: 的前缀了

/***** namespace_example.cpp *****/
#include <iostream>
using namespace std;
namespace A {
    	//自定义命名空间A
	int x = 1;
	void fun() {
    
		cout<<"A namespace"<<endl;
	}
}
using namespace A;	//声明使用命名空间A
int main(){
    
	fun();	//声明使用命名空间A后,可直接使用fun()
	A::x = 3;	//将A命名空间下的x重新赋值为3
	cout<<A::x<<endl;
	A::fun();
	return 0;
}

执行下面的指令开始编译

g++ namespace_example.cpp -o namespace_example

执行./namespace_example后结果如下

A namespace
3
Anamespace

二、C++面向对象

面向对象的三大特征是继承,多态和封装

2.1 类和对象

类是 C++ 的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员,函数在一个类中被称为类的成员。从类中实例化对象分两种方法,一种是从栈中实例化对象,一种是从堆中实例化对象

/***** class_dog_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    		//定义一个类
public:			//访问限定符public(公有的),不写的话默认是private
	string name;
	int age;
	
	void run() {
    	//定义一个方法
		cout<<"小狗的名字是:"<<name<<","<<"年龄是"<<age<<endl;
	}
};

int main() {
    
	/* 从栈中实例化一个对象dog1 */
	Dog dog1;	
	dog1.name = "旺财";	//为dog1的成员变量赋值
	dog1.age = 2;		//为dog1的成员变量赋值
	dog1.run();			//调用run()方法,打印dog1的相关变量信息
	/* 从堆中实例化对象,使用关键字new的都是从堆中实例化对象 */
	Dog *dog2 = new Dog();	
	if (NULL == dog2) {
    	//从堆中实例化对象需要开辟内存,指针会指向那个内存
		return 0;
	}
	dog2->name = "富贵";	//为dog2的成员变量赋值
	dog2->age = 1;			//为dog2的成员变量赋值
	dog2->run();			//调用run()方法,打印dog2的相关变量信息

	delete dog2;			//释放内存
	dog2 = NULL;			//将dog2重新指向NULL
	return 0;
}

执行下面的指令开始编译

g++ class_dog_example.cpp -o class_dog_example

执行./class_dog_example后结果如下

小狗的名字是:旺财,年龄是2
小狗的名字是:富贵,年龄是1
  • 构造函数与析构函数

构造函数在对象实例化时被系统自动调用,仅且调用一次。构造函数的特点如下:

  • 构造函数必须与类名同名
  • 可以重载,没有返回类型

析构函数在对象结束其生命周期时系统自动执行。析构函数的特点如下:

  • 析构函数的格式为~类名(),调用时释放内存(资源)
  • ~类名()不能加参数,没有返回值

定义类时, 如果没有定义构造函数和析构函数, 编译器就会生成一个构造函数和析构函数, 只是这个构造和析构函数什么事情也不做。当要使用构造函数和析构函数时就需要自己在类里添加

/***** structor_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    		//定义一个类,并在里面写了构造函数和析构函数
public:
	Dog();
	~Dog();
};

int main() {
    
	Dog dog;		//实例化一个dog对象
	cout<<"构造与析构函数示例"<<endl;
	return 0;
}
//类的函数可在类里实现,也可在类外实现,在类外实现时需要使用“::”
Dog::Dog() {
    
	cout<<"构造函数执行! "<<endl;
}

Dog::~Dog() {
    
	cout<<"析构函数执行! "<<endl;
}

执行下面的指令开始编译

g++ structor_example.cpp -o structor_example

执行./structor_example后结果如下

构造函数执行!
构造与析构函数示例
析构函数执行!
  • this 指针

每个对象都拥有一个 this 指针, this 指针记录对象的内存地址。this 指针是指向类自身数据的指针, 简单的来说就是指向当前类的当前实例对象。关于类的 this 指针有以下特点:

  • this 只能在成员函数中使用, 全局函数、静态函数都不能使用 this
  • this 在成员函数的开始前构造,在成员函数的结束后清除
  • this 指针会因编译器不同而有不同的放置位置。可能是栈,寄存器或者全局变量
/***** this_pointer_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    
public:
	string name;
	void func();
};

int main() {
    
	Dog dog;
	dog.func();
	return 0;
}
//在类的成员函数里使用了this指针, 并指向了类里的成员name
void Dog::func() {
    
	this->name = "旺财";
	cout<<"小狗的名字叫: "<<this->name<<endl;
}

执行下面的指令开始编译

g++ this_pointer_example.cpp -o this_pointer_example

执行./this_pointer_example后结果如下

小狗的名字叫:旺财
2.2 继承

面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,使得创建和维护一个应用程序变得更容易。也达到了重用代码功能和提高执行效率的效果。

当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。一个类可以派生自多个类,这意味着,可以从多个基类继承数据和函数。

定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:

class derived-class: access-specifier base-class
//访问修饰符 access-specifier是 public/protected/private中的一个
//base-class 是之前定义过的某个类的名称
//若未使用访问修饰符access-specifier,则默认为private

继承的方式有如下三种:

  • 公有继承(public):当一个类派生继承公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问
  • 保护继承(protected): 当一个类派生继承保护基类时,基类的公有和保护成员将成为派生类的保护成员
  • 私有继承(private):当一个类派生继承私有基类时,基类的公有和保护成员将成为派生类的私有成员
/***** inherit_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;
/* 动物类,抽象出颜色和体重,这两种动物都具有的属性 */
class Animal {
    	//基类
public:
	string color;	//颜色成员变量
	int weight;		//体重成员变量
};
/* 狗类继承了动物基类,并在狗类里添加自己的属性 */
class Dog : public Animal {
    	//派生类,公有继承了基类
public:
	string name;
	int age;
	void run();
};

int main() {
    
	Dog dog;
	dog.name = "旺财";
	dog.age = 2;
	dog.color = "黑色";
	dog.weight = 120;
	cout<<"狗的名字叫: "<<dog.name<<endl;
	cout<<"狗的年龄是: "<<dog.age<<endl;
	cout<<"狗的毛发颜色是: "<<dog.color<<endl;
	cout<<"狗的体重是: "<<dog.weight<<endl;
	return 0;
}

执行下面的指令开始编译

g++ inherit_example.cpp -o inherit_example

执行./inherit_example后结果如下

狗的名字叫:旺财
狗的年龄是:2
狗的毛发颜色是:黑色
狗的体重是:120
2.3 重载

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

  • 函数重载:在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同
/***** func_overloading.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    
public:
	string name;
	void getWeight(int weight) {
    	//写了一个方法,以int类型作为参数
		cout<<name<<"的体重是: "<<weight<<"kG"<<endl;
	}
	//以相同的函数名 getWeight,不同的参数类型 double weight,构成了函数重载
	void getWeight(double weight) {
    	
		cout<<name<<"的体重是: "<<weight<<"kG"<<endl;
	}
};

int main() {
    
	Dog dog;
	dog.name = "旺财";
	dog.getWeight(10);	//传进不同的参数,程序会匹配不同的重载函数
	dog.getWeight(10.5); //传进不同的参数,程序会匹配不同的重载函数
	return 0;
}

执行下面的指令开始编译

g++ func_overloading.cpp -o func_overloading

执行./func_overloading后结果如下

旺财的体重是:10KG
旺财的体重是:10.5KG
  • 运算符重载:实质就是函数重载或多态,目的在于让人能够用同名的函数来完成不同的基本操作。重载运算符的格式如下:
<返回类型说明符> operator <运算符符号>(<参数表>)
{
    
	<函数体>
}
/***** operator_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    
public:
	int weight;
	//重载“+”运算符,注意函数必须与类名同名,把Dog对象作为传递
	//使用this运算符进行访问,然后返回一个dog对象
	Dog operator+(const Dog &d) {
    
		Dog dog;
		dog.weight = this->weight + d.weight;
		return dog;
	}
};

int main() {
    
	Dog dog1;
	Dog dog2;
	Dog dog3;

	dog1.weight = 10;
	dog2.weight = 20;
	dog3 = dog1 + dog2;
	cout<<"第三只狗的体重是: "<<dog3.weight<<endl;
	return 0;
}

执行下面的指令开始编译

g++ operator_example.cpp -o operator_example

执行./operator_example后结果如下

第三只狗的体重是:30
2.4 多态

C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。形成多态必须具备三个条件:必须存在继承关系;继承关系必须有同名虚函数;存在基类类型的指针或者引用,通过该指针或引用调用虚函数

虚函数:是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。虚函数声明如下: virtual ReturnType FunctionName(Parameter) 虚函数必须实现,如果不实现,编译器将报错

纯虚函数:若在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是在基类中又不能对虚函数给出有意义的实现,这时就会用到纯虚函数。 纯虚函数声明如下:virtual void funtion1()=0 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用

/***** polymorphism_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;
/* 定义一个动物类 */
class Animal {
    
public:
	virtual void run() {
    	//虚函数
		cout<<"Animal 的 run()方法"<<endl;
	}
};
/* 定义一个狗类,并继承动物类 */
class Dog : public Animal {
    
public:
	void run() {
    
		cout<<"Dog 的 run()方法"<<endl;
	}
};
/* 定义一个猫类,并继承动物类 */
class Cat : public Animal {
    
public:
	void run() {
    
		cout<<"Cat 的 run()方法"<<endl;
	}
};

int main() {
    
	/* 声明一个 Animal 的指针对象,注:并没有实例化 */
	Animal *animal;	
	Dog dog;		/* 实例化 dog 对象 */	
	Cat cat;		/* 实例化 cat 对象 */	
	animal = &dog;	/* 存储 dog 对象的地址 */	
	animal->run();	/* 调用 run()方法 */	
	animal = &cat;	/* 存储 cat 对象的地址 */	
	animal->run();	/* 调用 run()方法 */
	return 0;
}

执行下面的指令开始编译

g++ polymorphism_example.cpp -o polymorphism_example

执行./polymorphism_example后结果如下

Dog的run()方法
Cat的run()方法
2.5 数据封装

封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据隐藏。

数据封装是一种把数据和操作数据的函数捆绑在一起的机制, 数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制, C++ 通过创建类来支持封装和数据隐藏(public、protected、 private)

/***** encapsulation_example.cpp *****/
#include <iostream>
#include <string>
using namespace std;

class Dog {
    
public:
	string name;
	//在构造函数里初始化total的数量
	Dog(int i = 0) {
    
		total = i;
	}
	//在这个方法里,将获得的食物份数赋值给total
	void addFood(int number) {
    
		total = total + number;
	}
	//在这个方法里,将返回食物的总份数
	int getFood() {
    
		return total;
	}
private:
	int total;
};

int main() {
    
	Dog dog;
	dog.name = "旺财";
	dog.addFood(3);
	dog.addFood(2);
	cout<<dog.name<<"总共获得了"<<dog.getFood()<<"份食物"<<endl;
	return 0;
}

执行下面的指令开始编译

g++ encapsulation_example.cpp -o encapsulation_example

执行./encapsulation_example后结果如下

旺财总共获得了5份食物
2.6 数据抽象

数据封装是一种把数据和操作数据的函数捆绑在一起的机制, 而数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。

数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节。数据抽象是一种依赖于接口和实现分离的编程(设计)技术。数据抽象的好处:

  • 类的内部受到保护,不会因无意的用户级错误导致对象状态受损
  • 类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告
2.7 接口

接口描述了类的行为和功能,而不需要完成类的特定实现。 C++ 接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念。 如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 “= 0” 来指定的

设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。因此,如果一个 ABC 的子类需要被实例化,则必须实现每个虚函数,这也意味着 C++ 支持使用 ABC 声明接口。如果没有在派生类中重写纯虚函数,就尝试实例化该类的对象,会导致编译错误。可用于实例化对象的类被称为具体类

/***** abstract_class.cpp *****/
#include <iostream>
using namespace std;
/* 定义一个动物类 */
class Animal {
    
public:
	virtual void run() = 0;
};
/* 定义一个狗类,并继承动物类 */
class Dog : public Animal {
    
public:
	void run() {
    
		cout<<"Dog 的 run()方法"<<endl;
	}
};
/* 定义一个猫类,并继承动物类 */
class Cat : public Animal {
    
public:
	void run() {
    
		cout<<"Cat 的 run()方法"<<endl;
	}
};

int main() {
    	
	Dog dog;	/* 实例化 dog 对象 */	
	Cat cat;	/* 实例化 cat 对象 */	
	dog.run();	/* dog 调用 run()方法 */	
	cat.run();	/* cat 调用 run()方法 */
	return 0;
}

执行下面的指令开始编译

g++ abstract_class.cpp -o abstract_class

执行./abstract_class后结果如下

Dog的run()方法
Cat的run()方法
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Chuangke_Andy/article/details/129873636

智能推荐

判断一个经纬度在另外一个经纬度的方向_判断一个点在另外一个点的什么方向-程序员宅基地

文章浏览阅读2.9k次。public static void main(String[] args) { Test test = new Test(); String str=getDirection(“”,104.735699,34.569058,104.754925); System.out.println(str); } public s_判断一个点在另外一个点的什么方向

策略模式Strategy-程序员宅基地

文章浏览阅读53次。原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11400764.html1. 定义定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。2.结构图Strategy:策略接口,用来约束一系列具体的策略算法。Context使用这个接口来调用具体的策略实现..._axl各策略

黑马程序员——其他4:JDK1.5新特性介绍-程序员宅基地

文章浏览阅读355次。基本数据对象包转类及其方法介绍

Oracle 12c RAC 集群使用 GNS 实现 SCAN_rac scan dns gns-程序员宅基地

文章浏览阅读1.9w次。注:本文谢绝转载! 1 说明 在前面的Blog中,讲过RAC 中SCAN 的配置有三种方式:(1) /etc/hosts(2) DNS(3) GNS 具体链接如下:Oracle RAC 集群 SCAN 说明http://blog.csdn.net/tianlesoftware/article/details/42712979 Oracle 12c RAC 集群使用DNS 实现 SCANhttp_rac scan dns gns

让Spring 3中jsp的数据对象使用懒加载(FetchType.LAZY)与Controller的JSR 303并存-程序员宅基地

文章浏览阅读87次。本文出处:http://blog.csdn.net/chaijunkun/article/details/9083171,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。最近维护一个之前做的项目,项目采用的是spring 3和hibernate 4 JPA做的。由于当时做项目的时候经验偏少,又图省事,所以使用了Hibernate..._jsp 如何对多个文件懒加载

全方位讲解VoIP 的原理及技术知识_voip原理图-程序员宅基地

文章浏览阅读2.1k次。通过因特网进行语音通信是一个非常复杂的系统工程,其应用面很广,因此涉及的技术也特别多,其中最根本的技术是VoIP (Voice over IP)技术,可以说,因特网语音通信是VoIP技术的一个最典型的、也是最有前景的应用领域。因此在讨论用因特网进行语音通信之前,有必要首先分析VoIP的基本原理,以及VoIP中的相关技术问题。一、VoIP的基本传输过程传统的电话网是以电路交换方式传输语音,所要求的传_voip原理图

随便推点

莫比乌斯反演--汇总学习博客-程序员宅基地

文章浏览阅读236次。学习博客: 学习博客1 ppt 带示例的博客2 博客3入门题:HDU1695 题解1 优化根号n版GCDGiven 5 integers: a, b, c, d, k, you’re to find x in a…b, y in c…d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x

【Spring注解源码】@PostConstruct,@PreDestory,BeanPostProcessor后置处理器_@postconstruct 对应的后置-程序员宅基地

文章浏览阅读146次。BeanPostProcessor后置处理器:测试初始化和初始化之后执行_@postconstruct 对应的后置

BIM模型轻量化的方法总结_bim轻量化-程序员宅基地

文章浏览阅读1k次。面向城市、园区、交通等数字孪生应用场景中,BIM模型的数据量非常大,千万级以上的三角面数与上万构件数会极大增加硬件的性能消耗。在仿真场景实时动态加载与高效流畅渲染层面就需要针对BIM模型进行全方位的优化。 BIM数据轻量化处理方面,可以通过单体BIM数据减面、同类型BIM数据实例化、合并多个BIM构建的方式来减少BIM模型的面数与构建来优化数据;对于不能进行优化处理的BIM数据类型,可以采用多级LOD进行数据的优化,从而减少硬件的性能消耗,有效提升场景渲染流畅性。_bim轻量化

CentOS7系统安装Git详细步骤_centos 安装 git-lfs-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏4次。本文详细介绍了在centos7 系统安装git工具的详细步骤_centos 安装 git-lfs

java的json解析工具_java 写一个JSON解析的工具类-程序员宅基地

文章浏览阅读456次。上面是一个标准的json的响应内容截图,第一个红圈”per_page”是一个json对象,我们可以根据”per_page”来找到对应值是3,而第二个红圈“data”是一个JSON数组,而不是对象,不能直接去拿到里面值,需要遍历数组。下面,我们写一个JSON解析的工具方法类,如果是像第一个红圈的JSON对象,我们直接返回对应的值,如果是需要解析类似data数组里面的json对象的值,这里我们构造方法..._java json.parseobject报错,用工具可以解析

BZOJ 3238 AHOI2013 差异 后缀自动机_bzoj3238 sam-程序员宅基地

文章浏览阅读2.4k次。题目大意:给定一个字符串,求Σ[1前两项是可以O(1)求的 我们要求的就是LCP之和对反串建立后缀自动机 那么parent指针连成的树就是后缀树直接在后缀树上DP就行- -对于每个节点统计所有子树两两right集合大小乘积之和乘上这个节点的深度即可QY神在学校讲了一天的SAM。。。 现在我觉得我还是回去学大型建筑机械吧233- -#include #include #i_bzoj3238 sam