Qt 的C++基础

1:C++基础

1: C++的输入输出方式

// 在 C 语言里,我们是这样输入或者输出的

在这里插入图片描述

//在 C++里,我们使用以 cin 和 cout 代替了 scanf 和 printf。在输入和输出的流程上是不变的,只是关键字变了,用法也变了。

在这里插入图片描述

// C++的 I/O 语法方式如下

/*  
1:cout 语法形式:
	x 可以是任意数据类型,甚至可以写成一个表达式,这比 C 语言需要指定数据类型方便多,endl 指的是换行符,与 C 语言的“\n”效果一样
*/
cout << x << endl;


2:C++之命名空间 namespace

在第 1.3 小节里我们已经使用过命名空间,如下代码第 2 行。using namespace std;同时我们 要注意第 1 行,不能写成 iostream.h,有.h 的是非标准的输入输出流,c 的标准库。无.h 的是标 准输入输出流就要用命名空间。
using 是编译指令,声明当前命名空间的关键词。可以从字面上理解它的意思,using 翻译 成使用。这样可以理解成使用命名空间 std。因为 cin 和 cout 都是属于 std 命名空间下的东西, 所以使用时必须加上 using namespace std;这句话。cin 和 cout 可以写 std::cin 和 std::cout,“::” 表示作用域,cin 和 cout 是属于 std 命名空间下的东西,这里可以理解成 std 的 cin 和 std 的 cout。
#include <iostream>
using namespace std;
int main()
{
    cout << "Hello, World!" << endl;
    return 0;
}

3:C++面向对象

3-1: 类和对象
从类中实例化对象分两种方法,一种是从栈中实例化对象,一种是从堆中实例化对象。 下面以自定义狗类介绍如何自定义类和如何使用对象。
#include <iostream>
#include <string>

using namespace std;

class Dog {
    // 公共的
	public:
		string name;
		int age;
		void run() {
			cout<<"小狗的名字是:"<<name<<","<<"年龄是"<<age<<endl;
		}
};

int main() {
    // 从栈中实例化一个对象 dog1(可以随意起名字)
	Dog dog1;
	dog1.name = "旺财";
	dog1.age = 2;
	dog1.run();
	// 从堆中实例化对象,使用关键字 new 的都是从堆中实例化对象
	Dog *dog2 = new Dog();
    // 如果 new 没有申请内存成功,p 即指向 NULL,程序就自动退出
    // 下面的就不执行了,写这个是为了严谨
	if (NULL == dog2) {
		return 0;
	}
	dog2->name = "富贵";
	dog2->age = 1;
	dog2->run();

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

3-1-1: 构造函数与析构函数
什么是构造函数?构造函数在对象实例化时被系统自动调用,仅且调用一次。构造函数出 现在哪里?前面我们学过类,实际上定义类时,如果没有定义构造函数和析构函数,编译器就 会生成一个构造函数和析构函数,只是这个构造和析构函数什么事情也不做,所以我们不会注 意到一点。
构造函数的特点如下:
1:构造函数必须与类名同名
2:可以重载
3:没有返回类型,即使是 void 也不行
什么是析构函数?与构造函数相反,在对象结束其生命周期时系统自动执行析构函数。实 际上定义类时,编译器会生成一个析构函数。
析构函数的特点如下
1:析构函数的格式为~类名()
2:调用时释放内存(资源)
3:~类名()不能加参数
4:没有返回值,即使是 void 也不行
// 下面我们通过简单的例子来说明构造函数和析构函数的使用
#include <iostream>
#include <string>

using namespace std;
class Dog {
	public:
		Dog();
		~Dog();
};
int main() {
	Dog dog;
	cout<<"构造与析构函数示例"<<endl;
	return 0;
}

// 类的函数可以在类里实现,也可以在类外实现,不过在类外实现时需要使用“::”
Dog::Dog() {
	cout<<"构造函数执行!"<<endl;
}
// 类的析造函数定义在类的外面
Dog::~Dog()
{
	cout<<"析构函数执行!"<<endl;
}
3-1-2:this 指针
每个对象都拥有一个 this 指针,this 指针记录对象的内存地址。 在 C++中,this 指针是指向类自身数据的指针,简单的来说就是指向当前类的当前实例对象
关于类的 this 指针有以下特点
1:this 只能在成员函数中使用,全局函数、静态函数都不能使用 this
2:this 在成员函数的开始前构造,在成员函数的结束后清除
3:this 指针会因编译器不同而有不同的放置位置。可能是栈,也可能是寄存器,甚至全 局变量
#include <iostream>
#include <string>

using namespace std;

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

int main() {
	Dog dog;
	dog.func();
	return 0;
}

void Dog::func() {
    // 在类的成员函数里使用了 this 指针,并指向了类里的成员 name。
    // 先将 name 赋值叫“旺财”,然后我们打印 name 的值。
	this->name = "旺财";
	cout<<"小狗的名字叫:"<<this->name<<endl;
}

3-2:继承

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了 一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生 类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名
// class derived-class: access-specifier base-class
下面来捋一捋继承的方式,例子都是以公有成员和公有继承来说明,其他访问修饰符和其 他继承方式,大家可以在教程外自己捋一捋。这个公有成员和继承方式也没有什么特别的,无 非就是不同的访问权限而已,可以这样简单的理解。
1:公有继承(public)
当一个类派生继承公有基类时,基类的公有成员也是派生类的公有成 员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但 是可以通过调用基类的公有和保护成员来访问
2:保护继承(protected)
当一个类派生继承保护基类时,基类的公有和保护成员将成为派 生类的保护成员
3:私有继承(private)
当一个类派生继承私有基类时,基类的公有和保护成员将成为派生类 的私有成员
#include <iostream>
#include <string>
using namespace std;

/*动物类,抽象出下面两种属性,
 *颜色和体重,是每种动物都具有的属性
 */
class Animal
{
public:
	/* 颜色成员变量 */
	string color;
	/* 体重成员变量 */
	int weight;
};

/*让狗类继承这个动物类,并在狗类里写自己的属性。
 *狗类拥有自己的属性name,age,run()方法,同时也继承了
 *动物类的color和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;
}


3-3:重载

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符 重载
3-3-1:函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指 参数的个数、类型或者顺序)必须不同。我们不能仅通过返回类型的不同来重载函数。
通俗来讲就是函数名相同,参数不同,编译器会自动根据不同的参数执行想对应的函数。
#include <iostream>
#include <string>
using namespace std;

class Dog
{
public:
	string name;
	void getWeight(int weight) {
		cout<<name<<"的体重是:"<<weight<<"kG"<<endl;
	}

	void getWeight(double weight) {
		cout<<name<<"的体重是:"<<weight<<"kG"<<endl;
	}
};

int main()
{
	Dog dog;
	dog.name = "旺财";
	dog.getWeight(10);
	dog.getWeight(10.5);
    return 0;
}
3-3-2:运算符重载
#include <iostream>
#include <string>
using namespace std;

class Dog
{
public:
	int weight;
	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;
}

3-4:多态

C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数; 形成多态必须具备三个条件
1:必须存在继承关系
2:继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字 virtual 声明的函数,在派 生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数
3:存在基类类型的指针或者引用,通过该指针或引用调用虚函数
3-4-1:虚函数
是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时, 会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类 型来选择调用的函数,这种操作被称为动态链接,或后期绑定。虚函数声明如下:virtual ReturnType FunctionName(Parameter) 虚函数必须实现,如果不实现,编译器将报错
3-4-2:纯虚函数
若在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基 类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。纯虚函数声明如下: virtual void funtion1()=0; 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。 包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的 指针或引用。
#include <iostream>
#include <string>
using namespace std;

/* 定义一个动物类 */
class Animal
{
public:
    // void run()
    // 基类 Animal 类的 run()方法前面加了关键字 virtual。这样让基类 Animal 类的 run()方法变成了虚函数
    // 道虚函数是 C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访
问派生类定义的函数
	virtual void run() {
		cout<<"Animal的run()方法"<<endl;
	}
};

/* 定义一个狗类,并继承动物类 */
class Dog : public Animal
{
public:
    // void run()
    // 可以理解是 animal 指针实例化的过程。
    // 当基类的 run()方法定义成虚函数,编译器不静态链接到该函数,它将链接到派生类的 run()方法,进行实例化
	void run() {
		cout<<"Dog的run()方法"<<endl;
	}

};

/* 定义一个猫类,并继承动物类 */
class Cat : public Animal
{
public:
    // void run()
    // 可以理解是 animal 指针实例化的过程。
    // 当基类的 run()方法定义成虚函数,编译器不静态链接到该函数,它将链接到派生类的 run()方法,进行实例化
	void run() {
		cout<<"Cat的run()方法"<<endl;
	}

};

int main()
{
	/* 声明一个Animal的指针对象,注:并没有实例化 */
	Animal *animal;
	/* 实例化dog对象 */
	Dog dog;
	/* 实例化cat对象 */
	Cat cat;

	/* 存储dog对象的地址 */
	animal = &dog;
	/* 调用run()方法 */
	animal->run();

	/* 存储cat对象的地址 */
	animal = &cat;
	/* 调用run()方法 */
	animal->run();
    return 0;
}

3-4-3:数据封装
封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受 到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据 隐藏。
数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴 露接口而把具体的实现细节隐藏起来的机制,C++ 通过创建类来支持封装和数据隐藏(public、 protected、private)
#include <iostream>
#include <string>
using namespace std;

class Dog
{
public:
	string name;
	Dog(int i = 0)
	{
		total = i;
	}
	void addFood(int number) {
		total = total + number;
	}
	int getFood() {
		return total;
	}
    // 通过2个函数对私有变量进行操作
private:
	int total;
};


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


3-4-4:数据抽象
数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息 而不呈现细节。数据抽象是一种依赖于接口和实现分离的编程(设计)技术
数据抽象的好处:
1. 类的内部受到保护,不会因无意的用户级错误导致对象状态受损
2. 类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要 求不改变用户级代码的错误报告
就 C++ 编程而言,C++ 类为数据抽象提供了可能。它们向外界提供了大量用于操作对象 数据的公共方法,也就是说,外界实际上并不清楚类的内部实现。 其实像 cout 这个对象就是一个公共的接口,我们不必要知道 cout 是如何在屏幕上显示内容 的。cout 已经在底层实现好了
// 数据封装是一种把数据和操作数据的函数捆绑在一起的机制
// 而数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制

3-5: 接口(抽象类)

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值