C++学习(1)-------基本语法介绍

133 阅读4分钟
C++ 基本语法
C++基础语法说明
基本形式NA
命名空间NA
构造函数和析构函数NA
实例化方法NA
指针和引用NA
静态成员NA
继承NA
虚函数和纯虚函数NA
友元函数和友元类NA
#####基本形式
basicCplusplus.h 包含类的声明
basicCplusplus.cpp 类的具体实现
basicCplusplus.h:
#ifndef _BASICCPLUSCPLUSDEMO_
#define _BASICCPLUSCPLUSDEMO_

#include <string>

#ifdef __cplusplus
extern  "C" {
#endif

using namespace std;

class basicCplusplus {
public:
	basicCplusplus();
	~basicCplusplus() = default;
};

#ifdef __cplusplus
}
#endif
#endif

basicCplusplus.cpp:

#include "basicCplusplus.h"
#include <iostream>
#include <memory>

basicCplusplus::basicCplusplus() {
	string strclassa("classa");
	basicClass classa(strclassa);
	cout << "basicCplusplus get string: " << classa.getString() << endl;

	string strclassb("classb");
	basicClass* pclassb = new basicClass(strclassb);

	//string temp("HelloWorld");
	auto temp = new string("Hellonew");
	auto pclassc = make_shared<basicClass>(*temp);
	cout << "basicCplusplus get string: " << pclassc->getString() << endl;

	basicClass* pclassd = classa + (*pclassb);
	cout << "opearator demo pclassd get string" << pclassd->getString() << endl;
}

#####构造函数和析构函数 构造函数是一种特殊类型的成员函数,主要特点如下:

  • 每个类必须存在一个构造函数,否则编译器会默认产生一个(没有参数,不做任何事)
  • 没有返回值
  • 在对象创建的时候被调用
  • 可以重载,可以使用默认参数,不能被继承

析构函数和构造函数特点基本一致,只是是对象被销毁的时候创建

构造函数可以使用初始化参数列表:

basicClass::basicClass():mstr("basicClass") {
	cout << "construct basic class" << endl;
}

构造函数可以使用默认参数:

class basicClass {
public :
	basicClass();
    basicClass(basicClass& p);
	inline basicClass(string str) {
		mstr = str;
	}
	~basicClass() = default;
	string getString();
	void setString();
	void setString(string str);
	void setString(char* array, uint8_t start = 0, uint8_t end = 0);
	basicClass* operator+(basicClass& p);
private:
	string mstr;
};

void basicClass::setString(char* array, uint8_t start, uint8_t end) {
	string tempstr(array);
	mstr = tempstr;
}

注意: 构造函数重载的时候,没有任何参数的构造函数称为默认构造函数,一个类中只能有一个默认构造函数

  • 拷贝构造函数 basicClass(basicClass& p) 表示拷贝构造函数,在对象之间互相赋值的时候使用,如下面的情形 basicClass a; basicClass demob(demoa); 注意拷贝构造函数的参数一定要是对象的引用,拷贝构造函数可以有其他的参数,但是要有默认值

如果类中没有显式定义拷贝构造函数,编译器会默认自动生成一个,自动生成的拷贝构造函数功能简单,只能将源对象的所有成员变量一一复制给当前创建的对象

由于类会自动生成拷贝构造函数,因此有些时候为了不让对象发生拷贝行为,我们可以显示声明一个拷贝构造函数,并将其设置为private属性,这是一个类设计的技巧

实例化方法

直接定义对象或者使用指针 demoClass a(para1, para2, ......) demoClass p = new demoClass(para1, para2, ......) auto pclassc = make_shared(para1, para2,.....); 对接上面定义的的 demoClass

	string strclassa("classa");
	basicClass classa(strclassa);
	cout << "basicCplusplus get string: " << classa.getString() << endl;

	string strclassb("classb");
	basicClass* pclassb = new basicClass(strclassb);

	//string temp("HelloWorld");
	auto temp = new string("Hellonew");
	auto pclassc = make_shared<basicClass>(*temp);
	cout << "basicCplusplus get string: " << pclassc->getString() << endl;

#####指针和引用 uint32_t tempa; uint32_t& refa = tempa; //定义一个引用 refa 指向tempa 变量

变量的指针表示的是变量的地址,我们一般说指针实际说的是指针变量,指针变量也是一种变量,只是这个变量特定用于存储其他变量的地址, 引用和之前的变量实际上一个东西,是原来变量的一个别名,对引用的赋值和加减操作都相当于直接对变量本身进行操作; 引用的使用限制:

  • 没有空引用的存在,引用一旦定义就必须绑定一个变量,绑定之后就不能再改变

一般能够使用引用的场景都可以使用指针,但是能使用指针的场景不一定能使用引用; 尽可能的使用引用,不得已的时候使用指针;

函数返回值是引用的情形
  • 函数直接返回对象 return 的时候有一个拷贝的过程,如果在函数内部定义对象,会先调用拷贝构造函数,再析构自身;

  • 函数返回对象的引用 return 的实际上是指向对象的指针,如果对象定义在栈上,函数返回后就会被回收,此时使用对象的引用就会出错

  • 函数返回对象的指针 最直接的方法,不能返回栈上变量的指针

complexDemoClass testreturnObject() {
	complexDemoClass a(1.0f, 1.1f);
	return a;
}

complexDemoClass& testreturnReference() {
	complexDemoClass a(1.0f, 1.1f);
	return a;
}

complexDemoClass* testreturnpointer() {
	complexDemoClass* ptr = new complexDemoClass(1.0f, 1.1f);
	return ptr;
}

{
	complexDemoClass democlassa = testreturnObject();
	democlassa.dumpClass();
	cout << "==============================================" << endl;
	complexDemoClass& democlassb = testreturnReference();
	democlassb.dumpClass();
	cout << "==============================================" << endl;
	complexDemoClass* demoptr = testreturnpointer();
	demoptr->dumpClass();
}

输出结果:

直接返回对象包含一次对象拷贝的过程
demoMain Run ....
construct complexDemoClass (a,b)
copy construct complexDemoClass
destruct ~complexDemoClass
dumpClass r = 1 t = 1.1
==============================================
直接返回栈上的对象的引用,等于返回栈上变量的地址,出现错误
construct complexDemoClass (a,b)
destruct ~complexDemoClass
dumpClass r = -9.25596e+61 t = 1.45625e-303
==============================================
new 出来的对象位于堆上,可以返回指针
construct complexDemoClass (a,b)
dumpClass r = 1 t = 1.1
destruct ~complexDemoClass

#####静态成员 C++ 中包含静态函数和静态变量两种

#####静态变量

  • 静态变量可以理解为定义在类中的全局变量,任然是全局变量的一种,只是享有类的范围,它是属于类而不属于某个对象,可以在没有对象创建的时候就进行操作;

  • 静态成员变量的初始化不能在类中,只能在类外并且在main函数之前,按照这样的格式进行初始化:变量类型 类名::变量名= 值,并且是先初始化再使用;

#####静态函数

  • 静态成员函数中不可以使用非静态成员,因为非静态成员是属于对象,而类的静态成员函数是属于类的;
  • 类的非静态成员函数中可以引用类的静态成员,反之不可以;
  • 静态成员函数没有this指针;
  • 父类中定义了静态成员,则整个继承体系中只有一个这样的成员,无论派生出多少个子类,静态成员是存储在全局区的
//header file
#ifndef _basicCPlusPlusB_
#define _basicCPlusPlusB_
#include <string>
#ifdef __cplusplus
extern  "C" {
#endif
using namespace std;
class basicCplusplusB {
public:
	basicCplusplusB();
	~basicCplusplusB() = default;
	static void staticfunction();
private:
	//static uint32_t a = 10;  //compile error
	static uint32_t a;
	uint32_t flag;
};

//cpp body file
#include "basicCplusplusB.h"
#include <iostream>

// init static variable
uint32_t basicCplusplusB::a = 10;

void basicCplusplusB::staticfunction() {
	//flag = 100; //compile error  only touch static var
	basicCplusplusB::a = 100;
}

basicCplusplusB::basicCplusplusB():flag(0) {
	cout << "basicCplusplusB static a: " << a << endl;
	basicCplusplusB::staticfunction();
	cout << "basicCplusplusB static a: " << a << endl;

}


#ifdef __cplusplus
}
#endif
#endif

#####继承 public 继承:也被称为类型继承 ,基类中所有的访问权限在派生类中不做改变; private 继承:也被称为实现继承,将基类中所有的公有成员变成自己的私有数据,这样派生类将不再支持基类的公有接口,公有和保护成员在派生类中成了私有,私有成员任为基类私有; protected 继承:公有和保护成员在派生类中成了保护成员,私有成员任为基类私有;

#####虚函数 虚函数 在基类的函数声明前加上virtual关键字,这个函数就是虚函数,这样如果派生类对虚函数重新定义,那么派生类的虚函数将会覆盖基类对应的虚函数的实现,如果通过基类的指针调用虚函数,那么将会调用这个指针所指向的具体对象的虚函数 如果派生类没有实现该函数,那么还是会调用基类这个已经实现的函数;

纯虚函数 如果想强制派生类实现这个函数,可以将其定义为纯虚函数。 virtual void busyticket() = 0;

抽象类 当类中存在纯虚函数的时候,这个类就是一个抽象类,仅仅用于向外提供接口,同时不能创建这个类的具体对象,否则将会产生编译错误 如果某个类从抽象类中派生,那么它必须实现其中的纯虚函数才能成为一个实体的类,否则将会继续保持抽象类的特征

#####友元函数和友元类 友元函数实际上是一个定义在类中的外部函数,它不属于任何类,使用friend类型声明之后,这个函数就可以成为类的友元函数,友元函数可以访问类中私有成员,友元函数可以是另一个类中的成员函数,也可以是一个全局的函数

友元函数跟类的成员函数的声明是相同的,只是它定义在类的外部,它不是类的成员函数,友元函数的声明位置既可以是类的public部分,也可是类的private部分,没有区别;函数可以是多个类的友元函数,只是需要分别在各个类中声明

一般来说:友元函数带有一个与其有好友关系的类类型的入口参数。因为友元函数不是与其有好友关系的类的成员函数,它没有this指针,所以它不能直接引用类成员的名字。它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员 下面demo 说明:

  • 友元函数一般是外部函数,可以通过形参的方式获取private 成员,也可以直接在函数内部访问到private 成员
  • 因为友元函数不是成员函数,所以声明为 static 没有什么意义
class demoClassA {
public:
	demoClassA():temp(100){
		cout << "construct demoClassA" << endl;
	}

	friend void friendFunctionA(); // friend 函数不是成员函数
	friend void friendFunctionB(demoClassA& p); // 传入参数的方法获取private 成员
	static friend void friendstaticFunctionC();
private:
	uint32_t temp;
};

void friendFunctionA() {
	demoClassA* p = new demoClassA();
	cout << "[friendFunctionA]get demoClassA private var: " << p->temp << endl;
}

void friendFunctionB(demoClassA& p) {
	cout << "[friendFunctionB]get demoClassA private var: " << p.temp << endl;
}

void friendstaticFunctionC() {
	demoClassA* p = new demoClassA();
	cout << "[friendstaticFunctionC] get demoClassA private var:" << p->temp << endl;
}

// test for friend function 
{
	friendFunctionA();
	demoClassA temp;
	friendFunctionB(temp);
	friendstaticFunctionC();
}

友元类是定义在另一个类中的普通类,因为需要访问另一个类中的隐藏信息,所以使用friend关键字声明为另一个类的友元类,成为另一个类的友元类后,友元类中的所有成员函数都成为另一个类的友元函数,可以访问另一个类中的隐藏信息 下面的 demo demoClassA 和 demoClassB 互为友元类,所以可以相互访问各自的私有成员

class demoClassA {
public:
	demoClassA() :tempvalA(100) {
		cout << "construct demoClassA" << endl;
	}

	void friendFunctionA();
	friend class demoClassB;
private:
	uint32_t tempvalA;
};

class demoClassB {
public:
	demoClassB() :tempvalB(1000) {
		cout << "construct demoClassA" << endl;
	}

	void friendFunctionB();
	friend class demoClassA;
private:
	uint32_t tempvalB;
};

void demoClassA::friendFunctionA()
{
	demoClassB classb;
	cout << "demoClassA get demoClassB private: " << classb.tempvalB << endl;
}


void demoClassB::friendFunctionB()
{
	demoClassA classa;
	cout << "demoClassA get demoClassB private: " << classa.tempvalA << endl;
}

#####命名空间 C++ 中name 可以是符号常量、变量、函数、结构、枚举、类和对象等等,在大型项目中,因为涉及到不同的开发人员和模块相互之间冲突的可能性很大,为此标准C++引入命令空间的概念(namespace)

######使用域解析操作符 使用域解析操作符可以实现全局变量和局部变量的声明

	{
		uint32_t a = 100;
		cout << "local variable " << a << endl;
		cout << "global variable a " << ::a << endl;
	}

######命名空间的定义和使用 使用如下形式,将符号常量、变量、函数、结构、枚举、类和对象 定义在命令空间的 { } 中 namespace demospaceb { uint32_t demoval = 20; }

  • 使用 namespace::变量 的形式引用,缺点是每个元素都要加上namespace 比较繁琐
  • 在文件开头使用 using namespace xx ,表明该文件中默认使用xx 的namespace
  • 也可以在函数中使用using namespace xx,表面该函数中默认使用xx 的namespace
uint32_t a = 10;

namespace demospacea {
	uint32_t demoval = 10;
}


namespace demospaceb {
	uint32_t demoval = 20;
}

void testnamespace() {
	{
		uint32_t a = 100;
		cout << "local variable " << a << endl;
		cout << "global variable a " << ::a << endl;
	}

	{
		demospacea::demoval = demospaceb::demoval + 10;
		cout << "demoval value: " << demospacea::demoval << endl;

	}

	{
		using demospacea::demoval;
		demoval = 1000;
		cout << "demospacea::demoval value: " << demospacea::demoval << endl;
		cout << "demospacea::demoval value: " << demospaceb::demoval << endl;
	}

}