C++初学习02


C++特殊成员

const成员

  • const数据成员
    • const类型变量是不可以修改,只读模式
    • 必须采用初始化参数列表方式进行初始化
  • const成员函数
    • 写法上, const写在函数后面
    • 常成员函数是不能够修改数据成员,只读数据成员
    • 常成员函数可以与普通函数同时存在
      • 普通函数和常成员函数相同时,普通对象优先调用普通函数
      • 普通对象可以调用常成员函数
  • const对象: const修饰的对象
    • 常对象只能调用常成员函数
#include <iostream>
#include <string>
using namespace std;
class MM 
{
public:
	MM(string name, int num) :num(num)
	{
		MM::name = name;  //可以用,也可以不用初始化列表
		//MM::num = 1001;  必须要用初始化参数列表方式初始化
	}
	void print() 
	{
		//不能修改
		//num = 1001;   错误,只读模式
		cout << name << " " << num << endl;
	}
	//常成员函数
	void print()const 
	{
		//name = "修改";   错误,常成员函数不能修改数据
		//num = 199;
		cout << "常成员函数" << endl;
	}
	void printData() 
	{
		cout << "普通函数" << endl;
	}
protected:
	string name;
	const int num;		//const数据成员
};
int main() 
{
	MM mm("对象", 18);
	mm.print();				//普通对象调用普通函数
	const MM cmm("常对象", 20);
	cmm.print();			//常对象调用常成员函数
	//cmm.printData();		//错误!,常对象只能调用普通函数
	return 0;
}

static成员

static成员是不属于对象,是属于类的,意味着是所有对象共有的,调用可以不需要对象,也可以用对象调用。当用对象调用时,static成员依旧受权限限定。

  • static数据成员

    • 必须在类外初始化,不再需要static修饰,但是需要类名限定

    • 类中初始化是错误的,不能采用初始化参数列表方式初始化

  • static成员函数

    • static写在函数前面即可

    • 调用非静态成员 必须要指定对象

  • static对象

    • 释放是最后释放的

#include <iostream>
using namespace std;
class MM 
{
public:
	MM(string name=""):name(name) 
	{
		num++;
	}
	static void printMM();
	static void printData(MM& mm) 
	{
		cout << mm.name <<" "<<num <<endl;
	}
protected:
	string name;
public:
	static int num;
};
//类外初始化,不再需要static修饰,但是需要类名限定
int MM::num = 1;
//类外初始化,不再需要static修饰
void MM::printMM() 
{
	//调用非静态数据成员,必须要指定对象
	//cout << name << endl;  当这个函数不采用对象去调用,name没有来源
	//静态调用静态,没什么要求
	cout << num << endl;
	cout << "静态成员函数" << endl;
}
int main() 
{
	//静态数据成员访问,可以不需要对象
	cout << MM::num << endl;
	//什么叫做共有的
	MM mm("mm");
	//静态数据成员可以通过对象去访问
	cout << mm.num << endl;      //此时num等于2
	MM array[3];			     //5
	MM* p = new MM("newMM");	 //6
	cout << MM::num << endl;
	cout << p->num << endl;
	cout << mm.num << endl;
	delete p;
	p = nullptr;
	//静态成员函数
	MM::printMM();
	mm.printMM();
	MM::printData(mm);
	return 0;
}

友元

友元用friend描述 ,友元只提供场所,赋予对象具有打破类的权限定(无视权限)

  • 友元函数
    • 普通友元函数
    • 以另一个类的成员函数充当友元函数,顺序如下:
      • B 类
      • A 类
      • A 类的友元函数(B类的成员函数)
  • 友元类
#include <iostream>
using namespace std;
class MM 
{
	friend class GG;
public:
	MM(string name, int age) :name(name), age(age) {}
protected:
	string name;
	int age;
};
class GG 
{
public:
	void print() 
	{
		MM mm("mm", 18);
		cout << mm.name << "\t" << mm.age << endl;
	}
	void printMM(MM& mm) 
	{
		cout << mm.name << "\t" << mm.age << endl;
	}
	MM& returnMM(MM& mm) 
	{
		return mm;
	}
protected:
};
//互为友元类的写法
class A 
{
	friend class B;
public:
	void printData();
protected:
	string data="A";
};
class B 
{
public:
	friend class A;
	void printData() 
	{
		A a;
		cout << a.data << endl;
	}
protected:
	string data = "B";
};
void A::printData() 
{
	B b;
	cout << b.data << endl;
}
int main() 
{
	MM mm("mm", 18);
	GG gg;
	gg.print();
	gg.printMM(mm);
	//cout << gg.returnMM(mm).name << endl;  错误,出了友元类,没有权限

	//互为友元
	B b;
	b.printData();
	A a;
	a.printData();
	return 0;
}

this指针与explicit 

  • explicit修饰构造函数使用,不让隐式转换构造
  • this指针
    • 避免形参名和数据成员同名,通指对象的地址
    • 充当函数返回值,返回对象自身,用*this表示对象本身
    • 静态成员函数中是不能使用this指针
#include <iostream>
using namespace std;
class MM 
{
public:
	explicit MM(int age) :age(age) {}
	void print() 
	{
		cout << age << endl;
	}
protected:
	int age;
};
class GG 
{
public:
	GG(string name, int age) :name(name), age(age) {}
	//普通函数不存在初始化参数列表
	void initData(string name, int age)
	{
		//类名限定 帮助计算机去识别
		GG::name = name;
		this->age = age;
	}
	void print() 
	{
		cout << this->name << " " << this->age << endl;
	}
	void printThis() 
	{
		cout << this << endl;
	}
	GG& returnGG() 
	{
		return *this;
	}
	void printGG2(GG& gg) {}
	static void printStatic() 
	{
		GG gg("this", 19);
		cout << gg.name << "\t" << gg.age << endl;
	}
protected:
	string name;
	int age;
};
int main() 
{
	//explicit 不让隐式转换构造
	//MM mm = 12;
	//MM temp = 1.33;
	MM temp(12);
	temp.print();

	GG gg("长沙吴彦祖", 28);
	gg.print();

	gg.initData("顿开吴彦祖", 38);
	gg.print();

	cout << &gg << endl;
	gg.printThis();

	GG boy("哥哥吴彦祖", 38);
	cout << &boy << endl;
	boy.printThis();

	gg.returnGG().returnGG().returnGG().returnGG().returnGG().returnGG().print();
		

	GG::printStatic();
	return 0;
}

小练习

  1. 实现string中创建方式:

  2. 通过实现data和c_str函数  打印字符串

  3. 实现append 实现字符串的链接

  4. 实现字符串比较

  5. 手写析构函数释放内存

#include <iostream>
#include <cstring>
using namespace std;
class mystring
{
public:
	//mystring() 
	//{
	//	strSize = 1;
	//	str = new char;
	//	*str='\0';
	//};
	mystring(const char* str="") 
	{
		strSize = strlen(str) + 1;
		mystring::str = new char[strSize];
		strcpy_s(mystring::str,strSize,str);
	}
	mystring(const mystring& object)
	{
		strSize = object.strSize;
		str = new char[strSize];
		strcpy_s(str, strSize, object.str);
	}
	char* c_str() 
	{
		return str;
	}
	char* data() 
	{
		return str;
	}
	mystring append(const mystring& object)
	{
        //"strcat_s()函数"使用时需要考虑内存空间大小问题,所以创建临时变量来设置大小
		mystring temp;
        //由于两个字符串各有一个"\0",所以-1删去一个"\0"
		temp.strSize = mystring::strSize + object.strSize-1;
		temp.str = new char[temp.strSize];
		memset(temp.str, 0, temp.strSize);
		strcat_s(temp.str, temp.strSize, str);
		strcat_s(temp.str, temp.strSize, object.str);
		return temp;
	}
	int compare(const mystring& object) 
	{
		return strcmp(str, object.str);
	}
	~mystring()
	{
		delete[] str;
		str = nullptr;
	}
protected:
	char* str;			//需要存储
	int  strSize;		
};
int main()
{
	{
		//1.实现string中创建方式
		mystring str1;
		mystring str2("ILoveyou");
		mystring str3(str1);
		mystring str4 = str2;
		//2.通过实现data和c_str函数 打印字符串
		cout << str2.c_str() << endl;  //打印ILoveyou
		cout << str2.data() << endl;   //打印ILoveyou
		//3.实现append 实现字符串的链接
		mystring strOne = "one";
		mystring strTwo = "two";
		mystring strThree = strOne.append(strTwo);
		cout << strThree.data() << endl;	    //onetwo
		//4.实现字符串比较
		cout << strOne.compare(strOne) << endl;	//0
	}
	//5.手写析构函数释放内存
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_59470001/article/details/127721630