C++复习笔记6

 1.String类的实现

注意深浅拷贝, C语言字符串拼接函数strcat()

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vld.h>
#include<assert.h>
using namespace std;

class String
{
	friend ostream& operator<<(ostream & cout, const String & s);
public:
	//String(const char* str)//处理了空指针,等效空串进行初始化
	//{
	//	if (str == nullptr)
	//	{
	//		this->m_data = (char*)malloc(sizeof(char));
	//		this->m_data[0] = '\0';
	//	}
	//	else
	//	{
	//		this->m_data = (char*)malloc(sizeof(char) * (strlen(str) + 1));
	//		strcpy(this->m_data, str);
	//	}
	//}

	String(const char* str = "")//等效写法 空指针和空串不同 没有处理空指针,更加严格
	{
		this->m_data = (char*)malloc(sizeof(char) * (strlen(str) + 1));
		strcpy(this->m_data, str);
	}

	String(const String& s)
	{
		this->m_data = (char*)malloc(sizeof(char) * (strlen(s.m_data) + 1));
		strcpy(this->m_data, s.m_data);
	}

	String& operator=(const String& s)
	{
		if (this != &s)
		{
			free(this->m_data);

			this->m_data = (char*)malloc(sizeof(char) * (strlen(s.m_data) + 1));
			strcpy(this->m_data, s.m_data);
		}
		return *this;
	}

	int Length() const
	{
		return strlen(this->m_data);
	}

	String operator+(const String& s)
	{
		String tmp(*this);
		tmp += s;
		return tmp;
	}

	String& operator+=(const String& s)
	{
		char* tmp = (char*)malloc(strlen(this->m_data) + strlen(s.m_data) + 1);
		strcpy(tmp, this->m_data);
		free(this->m_data);
		this->m_data = (char*)malloc(strlen(tmp) + strlen(s.m_data) + 1);
		strcat(tmp, s.m_data);
		strcpy(this->m_data, tmp);
		free(tmp);
		return *this;
	}

	char operator[](int pos) const
	{
		assert(pos >= 0 && pos < Length());
		return *(this->m_data + pos);
		//return this->m_data[pos];
	}

	~String()
	{
		if (this->m_data != nullptr)
		{
			free(this->m_data);
			this->m_data = nullptr;
		}
	}
private:
	char* m_data;
};

ostream& operator<<(ostream& cout, const String& s)
{
	cout << s.m_data << endl;
	return cout;
}

void test01()
{
	//String s(nullptr);//空指针不能拿来给字符串初始化或者赋值
	String s1("a,b,c");

	String s2 = s1;
}

void test02()
{
	String s1("abc");
	String s2("xyz");
}

void test03()
{
	const char* pstr = "ABCXYZ";
	cout << *(pstr + 1) << endl;
	cout << pstr[1] << endl;
	String s("ABC");
	cout << s[2] << endl;
}

void test04()
{
	String s1("abc");
	String s2("xyz");
	s1 += s2;
	cout << s1;
	String s3;
	s3 = s1 + s2;
	cout << s3;
}

int main()
{
	test04();
	system("pause");
	return 0;
}
2.    虽然构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化, 构造 函数体中的语句只能将其称作为赋初值 ,而不能称作初始化。因为 初始化只能初始化一次,而构造函数体内 可以多次赋值
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year, int month, int day)
	{
		this->m_year = year;
		this->m_month = month;
		this->m_day = day;
	}

private:
	int m_year;
	int m_month;
	int m_day;
};

3.初始化列表

1. 每个成员变量在初始化列表中 只能出现一次 ( 初始化只能初始化一次 )
2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
引用成员变量
const 成员变量
自定义类型成员 ( 该类没有默认构造函数 )
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。
#include<iostream>
using namespace std;

class Time
{
public:
	Time(int h=0 ) :hour(h) {}//有了全缺省有参构造可以不用默认构造

public:
	int hour;
};

class Date
{
public:
	Date(int day)
	{//有了全缺省有参构造可以不用默认构造对于t,也可以不用在函数体内或者初始化列表初始化
		this->day = day;
	}

public:
	Time t;
	int day;
};

int main()
{
	Date d(10);
	cout << d.t.hour << endl;

	system("pause");
	return 0;
}
#include<iostream>
using namespace std;

class Test1
{
 public:

	 Test1(int a)
	 {
		 t = a;
	 }

 private:
	 int t;
};

class Test2
{
public:

	Test2(int a,int b, const Test1& t):ref(a),ca(b),t1(t)
	{

	}

private:
	int& ref;
	const int ca;
	Test1 t1;
};

成员变量初始化顺序只与成员变量定义的顺序有关。

#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year, int month, int day) :m_month(month), m_year(year), m_day(day), ref(day),
		c_value(100)
	{

	}
private://初始化顺序只和这里的定义顺序有关,和上面的初始化列表无关
	int m_year;
	int m_month;
	int m_day;
	int& ref;//引用数据成员 必须通过参数列表进行初始化
	const int c_value;
};

int main()
{
	Date dt(2023, 2, 5);

	system("pause");
	return 0;
}

初始化顺序例题:

#include<iostream>
using namespace std;


class Test
{
public:
	Test(int a) :_a1(a), _a2(_a1)
	{

	}
	void Print()
	{
		cout << "_a1 =" << this->_a1 << " _a2 =" << this->_a2 << endl;
	}

private:
	int _a2;//先初始化a2在初始化a1
	int _a1;
};

int main()
{
	Test t(1);
	t.Print();

	system("pause");
	return 0;
}

        隐式类型转换的发生,不一定类只有一个成员变量,可以有多个(只要缺省值够多,只剩一个或者没有未缺省的值)就可以发生隐式类型转换。

       4 友元函数:友元函数可以在类外通过对象访问类的私有成员和保护成员(这个对象可以通过传参得到,也可以通过函数内部实例化得到)。友元函数可以直接访问类的私有成员和保护成员,它是定义在类外部普通函数,不属于任何类,但需要在类的内部声 明,声明时需要加friend关键字。因此友元函数没有this指针。

       注意:友元函数可访问类的私有和保护成员,但不是类的成员函数

                友元函数 不能用 const 修饰
                友元函数 可以在类定义的任何地方声明, 不受类访问限定符限制
                一个函数可以是多个类的友元函数
                友元函数的调用与普通函数的调用和原理相同
         输出运算符重载是友元函数的典型用法, 它为了实现cout在符号左边,成员符号右边必须写成友元函数实现。
#include<iostream>
using namespace std;

class A
{
friend void func(A& a);
public:

	A(int a = 0) :m_a(a) {}

private:
	int m_a;
};

void func(A& a)
{
	a.m_a = 30;
	cout << a.m_a << endl;

	A a1(50);
	a1.m_a = 60;
	cout << a1.m_a << endl;
}

int main()
{
	A a;
	func(a);

	system("pause");
	return 0;
}

一个函数可以做多个类的友元函数

#include<iostream>
using namespace std;

class B;

class A
{
friend void func(A& a, B& b);
public:
	A(int a = 0):m_a(a) {}

private:
	int m_a;
};

class B
{
friend void func(A& a, B& b);
public:
	B(int b=0):m_b(b){ }
private:
	int m_b;
};

void func(A& a, B& b)
{
	b.m_b = 20;
	a.m_a = 10;
	cout << a.m_a << " " << b.m_b << endl;
}

int main()
{
	A a;
	B b;
	func(a, b);

	system("pause");
	return 0;
}

成员函数做友元:让一个类的成员函数作为另一个类的友元函数。友元函数可以传参或者实例化目标类的对象也可以将目标类的对象、对象引用或者指针作为成员变量进行操作,这个对象(引用、指针)可以访问目标类的非公有成员。成员函数做友元会遇到类声明定义顺序的问题,这里是一个简单的例子,具体的各种情况会在后续博客中详细说明。

#include<iostream>
using namespace std;

class B;

class A
{
	friend void B::PrintA(A& a);
public:
	void PrintB(B& b);
	A(int a);
private:
	int m_a;
};

class B
{
friend void A:: PrintB(B& b);
public:
	B(int b);

	void PrintA(A& a);
private:
	int m_b;
};

A::A(int a = 0) : m_a(a) {}
B::B(int b = 0) : m_b(b) {}

void B::PrintA(A& a) 
{ a.m_a = 10;
cout << a.m_a << endl;
}

void A::PrintB(B& b)
{
	b.m_b = 20;
	cout << b.m_b << endl;
}

 正确代码:

#include<iostream>
using namespace std;

class B;

class A
{
//friend void B::PrintA(A& a);
public:
	void PrintB(B& b);
	A(int a);
private:
	int m_a;
};

class B
{
friend void A:: PrintB(B& b);
public:
	B(int b);

	//void PrintA(A& a);
private:
	int m_b;
};

A::A(int a = 0) : m_a(a) {}
B::B(int b = 0) : m_b(b) {}

//void B::PrintA(A& a) 
//{ a.m_a = 10;
//cout << a.m_a << endl;
//}

void A::PrintB(B& b)
{
	b.m_b = 20;
	cout << b.m_b << endl;
}

int main()
{
	A a;
	B b;
	a.PrintB(b);

	system("pause");
	return 0;
}

友元类:将一个类声明为另一个类的友元,友元类中所有的成员函数都是目标类的友元函数,可以在类外访问它的私有和保护成员。这里注意涉及到类的声明顺序,同样会在后续博客中进行说明。通过学习博客发现:

  • 类的声明相关资料:

        不完全类型(只声明的类)只能在非常有限的情况下使用:可以定义指向这种类型的指针或引用,也可以作为一个已经声明(但没有定义)的函数的参数或返回类型。
        对于一个类来说,在创建它的对象前必须首先完成类的定义,而不能仅仅被声明。否则编译器就无法了解这样的对象需要多少存储空间。类似的,类也必须首先被定义,然后才能用引用或者指针访问其成员。

    简而言之:

        如果在一段代码中使用了A类实例化对象(为堆区开辟对象)或者成员变量、成员函数,那么A类必须在这段代码之前定义;
        如果这段代码只使用A类来定义指针或者函数参数中的数据类型那么A类可以在这段代码上面声明,而在下面定义。
    ————————————————
    版权声明:本文为CSDN博主「拒绝省略号」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_49030008/article/details/123243230

  • #include<iostream>
    #include<vld.h>
    using namespace std;
    
    class B;
    class A
    {
    public:
    	A(int a, int b);
    	void setB(int i);
    	void getB();
    	~A();
    
    private:
    	int m_a;
    	B* pb;
    };
    
    class B
    {
    friend class A;
    public:
    	B(int b);
    
    private:
    	A* pa;
    	int m_b;
    };
    
    A::A(int a=0, int b=0):m_a(a), pb(new B(b)) {}
    A::~A() { delete pb; pb = nullptr; }
    B::B(int b = 0) :m_b(b) {}
    
    
    void A::setB(int i)
    {
    	this->pb->m_b = i;
    }
    
    void A::getB()
    {
    	cout << this->pb->m_b << endl;
    }
    
    int main()
    {
    	A a;
    	a.setB(30);
    	a.getB();
    
    system("pause");
    return 0;
    }
    
    
    
    #include<iostream>
    using namespace std;
    
    //class B;
    class A
    {
    friend class B;
    public:
    	A(int a = 0)
    	{
    		this->m_a = a;
    	}
    
    	/*void showB(const B& b)
    	{
    		cout << b.m_b << endl;
    	}*/
    
    private:
    	int m_a;
    };
    
    class B
    {
    //friend class A;
    public:
    	B(int b=0):m_b(b)
    	{
    	}
    
    	void showA(A& a)
    	{
    		cout << a.m_a << endl;
    	}
    
    private:
    	int m_b;
    };
    
    int main()
    {
    	A a(10);
    	B b;
    	b.showA(a);
    
    	system("pause");
    	return 0;
    }

1.友元关系不能被继承。

2.友元关系是单向的。

3.友元关系不具有传递性。

#include<iostream>
using namespace std;


//class B;
class A
{
friend class B;
public:
	A(int a = 0)
	{
		this->m_a = a;
	}

	/*void showB(const B& b)
	{
		cout << b.m_b << endl;
	}*/

private:
	int m_a;
};

class B
{
//friend class A;
public:
	B(int b=0):m_b(b)
	{
	}

	void showA(A& a)
	{
		cout << a.m_a << endl;
	}

private:
	int m_b;
};

int main()
{
	A a(10);
	B b;
	b.showA(a);

	system("pause");
	return 0;
}

静态成员:

静态成员函数:1.静态成员函数没有this指针,静态成员函数只能访问静态成员变量。静态成员函数也受到访问权限限定符的限制。

静态成员变量:1.在编译时分配内存。

                         2.必须在类外进行初始化。

                         3.由所有对象共享,它是属于整个类的。

                         4.可以使用对象名调用也可以使用类名调用。

                         5.静态成员也受到访问权限的限制。

#include<iostream>
using namespace std;

//普通可调常和静态 静态和常不能调普通
//Test* const this  普通方法this指针
// const Test* const this 常方法this指针
//静态成员函数 没有this指针

class Test
{
public:
	Test()//:m_value(0)//不能在类内初始化
	{
		this->m_data = 0;
		//this->m_value = 0;//不能在类内初始化
	}

	static void Show()
	{
		//cout << "m_data =" << m_data << endl;//静态成员函数只能调动静态成员
		cout << "m_value" << m_value << endl;
		//Fun();静态成员不能调普通成员
	}

	void Fun()//普通成员可以调动静态成员
	{
		this->m_data = 1;
		this->m_value = 10;
		this->Print();//普通方法可以调动常方法
		this->Show();//普通方法可以调静态方法
	}

	void Print() const
	{
		cout << "This is Print()" << endl;
		//Fun();//常方法不能调普通方法
	}

static int m_value;
private:
	int m_data;
};
//静态成员并不属于某个对象,属于整个类,所有对象共享
int Test::m_value = 0;//静态成员变量只能在类外进行初始化

void test01()
{
	Test t1;
	Test t2;
	cout << t2.m_value << endl;
	t1.m_value = 100;
	cout << t2.m_value << endl;
}

void test02()
{
	Test t1;
	t1.Fun();

	t1.Show();//类名和对象名都可以调用
	Test::Show();
}

void main()
{
	test02();
}

静态成员可以作类的实例化对象计数器:

#include<iostream>
using namespace std;

void fun2();

class Test
{
	friend void fun(const Test& t);//没有this指针
public:
	Test(int data =0)
	{
		this->m_data = data;
		this->count++;
	}

	static void ShowCount()
	{
		cout << count << endl;
	}

	~Test()
	{
		this->count--;
	}

private:
	int m_data;
	static int count;
};
int Test::count;

void test()
{
	
		Test t[100];
		Test::ShowCount();
	
		t[99].ShowCount();
	
	Test::ShowCount();
}

void main()
{
	test();
	system("pause");
}

c11规定,可以在声明类的成员变量时,给它赋默认值,即缺省参数。

#include<iostream>
using namespace std;

//友元函数可以在类外访问类的保护和私有成员
//友元函数不能用const修饰

class B
{
	friend class A;//友元类的使用
public:
	B(int b = 0) :m_b(b) {}

private:
	int m_b;
};

class A 
{
public:

	void Print()
	{
		cout << "sizeof(p)=" << sizeof(p) << endl;
		cout << "b.m_b=" << this->b.m_b<< endl;
		cout << "a.m_a=" << this->m_a << endl;
	}

private:
	int* p = (int*)malloc(sizeof(int));
	B b = 20;
	int m_a = 10;
};

int main()
{
	A a;
	a.Print();

	system("pause");
	return 0;
}

内部类,一个类的内部又定义了另一个类,主要注意在内部类实例化对象时,前面要加上外部类的作用域限定符。

#include<iostream>
using namespace std;

class Test
{
public:
	class Stu
	{
	public:
		void func()
		{
			cout << "AAA" << endl;
		}
	};

	void func()
	{
		cout << "BBB" << endl;
	}
};

int main()
{
	Test t;
	t.func();
    
	Test::Stu s;
	s.func();

	system("pause");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值