0
点赞
收藏
分享

微信扫一扫

C++:线上课程1_20(友元,静态成员,模板函数,模板类型)

AbrahamW 2022-03-16 阅读 55

友元,静态成员,模板函数,模板类型


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、值类别

1.左值和将亡值合称泛左值,纯右值和将亡值合称右值。

2.函数执行时生成将亡值,函数结束将亡值死亡

3.严格来讲,“左值"是表达式的结果的一种属性,但更为普遍地,我们通常用"左值"来指代左值表达式(正如上边一段中做的那样)。所谓左值表达式,就是指求值结果的值类别为左值的表达式。通常我们无需区分"左值"指的是前者还是后者,因为它们表达的是同一个意思,不会引起歧义。在后文中,我们依然用左值指代左值表达式。对于纯右值和将亡值,亦然。
4.右值引用
右值引用只能引用纯右值

int&& c=10;

在这里插入图片描述

    //右值拷贝构造(优先调用构建将亡值对象)
    String(String&& s)
    {
        cout << "move copy construcgt" << this << endl;
        str = s.str;
        s.str = NULL;
    }
    //右值赋值语句(优先调用构建将亡值对象)
    String& operator=(String&& s)
    {
        if (this != &s)
        {
            str = s.str;
            s.str = NULL;
        }
        cout << this << "move operator=:" << &s << endl;
        return *this;
    }
    //防止内存泄漏
    char* Release(char* p)
    {
        char* old = str;
        str = p;
        return old;
    }
class String
{
private:
	char* str;
	String(char* p, int)
	{
		str = p;
	}
public:
	String(const char* p = NULL) :str(NULL)
	{
		cout << "construct :" << this << endl;
		if (p != NULL)
		{
			str = new char[strlen(p) + 1];
			strcpy(str, p);
		}
		else
		{	/??
			str = new char[1];	 // str = NULL;
			*str = '\0';
		}
	}  // s1.str 
	~String()
	{
		cout << "destroy : " << this << endl;
		if (str != NULL)
		{
			delete[] str;
		}
		str = NULL;
	}

	//ostream& operator<<(const String* const this, ostream& out);
	ostream& operator<<(ostream  &out) const
	{
		if (str != NULL)
		{
			out << str;
		}
		return out;
	}
	String(const String& s):str(NULL)
	{
		cout << "copy construct : " << this << endl;
		str = new char[strlen(s.str + 1)];
		strcpy(str, s.str);
	}

	String operator+(const String& s) const
	{
		char* p = new char[strlen(this->str) + strlen(s.str) + 1];
		strcpy(p, this->str);
		strcat(p, s.str);
		return String(p,1);
	}
	String operator+(const char* s) const
	{
		char* p = new char[strlen(this->str) + strlen(s) + 1];
		strcpy(p, this->str);
		strcat(p, s);
		return String(p, 1);
		//return *this + String(s);
	}
#if 1
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			delete[]str;
			str = new char[strlen(s.str) + 1];
			strcpy(str, s.str);
			//delete[]str;
			//new (this) String(s);	// 
		}
		cout << this << " operator= : " << &s << endl;
		return *this;
	}
	String(String&& s)
	{
		cout << " move copy construcgt :" << this << endl;
		str = s.str;
		s.str = NULL;
	}  // String(s2);
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			s.str = Relese(s.str);
		}
		cout << this << " move operator=: " << &s << endl;
		return *this;
	}
#endif
	char* Relese(char* p)
	{
		char* old = str;
		str = p;
		return old;
	}
	// s1 = String();
};

// lvalue  xvalue  rvalue prvalue;	 //


ostream& operator<<(ostream& out, const String& s)
{
	s << out;  
	return out;
}

String operator+(const char* p, const String& s)
{
	return String(p) + s;
}
int main()
{
	String s1("yhping");
	String s2("hello");

	s1 = std::move(s2);

	return 0;
}

二、写时拷贝

1.柔性数组

(1)数组大小声明为0,或者不给出大小,称之为柔性数组。
注意:全局数组和局部数据不能这样定义

柔性数组是一种数组大小待定的数组。在c语言中,可以使用结构体产生柔性数组,结构体的最后一个元素可以是大小未知的数组。
data是标识符,不占用存储空间。

    //柔性数组
    struct StrNode
    {
        int ref;//引用个数
        int len;//字符串长度
        int size;//字符串空间大小
        char data[];
        //char data[0];
    };

(2)用途:长度为0的数组主要是为了满足长度可变的结构体,只能在结构体最后声明。
(3)用法︰在一个结构体的最后,声明一个长度为0的数组。就可以使得这个结构体是可变长的。对于编译器来说。此时长度为О的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量,数组名这个符号本身代表了一个不可修改的地址常量。但对于这个数组的大小,我们可以进行动态分配。
注意︰如果结构体是通过calloc、malloc或 realloc等动态分配方式生成,在不需要时要释放相应的空间。优点︰比起在结构体中声明一个指针变量、再进行动态分配的办法,这种方法效率要高。因为简单。
(4)缺点︰在结构体中,数组为О的数组必须在最后声明,在设计结构体类型有一定限制。

#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include<iostream>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
using namespace std;
class String
{
private:
    //柔性数组
    struct StrNode
    {
        int ref;//引用个数
        int len;//字符串长度
        int size;//字符串空间大小
        char data[];//
    };
    StrNode* pstr;
public:
    String(const char* p = NULL) :pstr(NULL)
    {
        if (p != NULL)
        {
            int len = strlen(p);
            pstr = (StrNode*)malloc(sizeof(StrNode) + len * 2 + 1);
            pstr->ref = 1;
            pstr->len = len;
            pstr->size = len * 2;
            strcpy(pstr->data, p);
        }
    }
    //拷贝构造函数
    String(const String& s) :pstr(NULL)
    {
        if (s.pstr != NULL)
        {
            pstr = s.pstr;
            pstr->ref += 1;
        }
    }
    //析构函数
    ~String()
    {
        if (pstr != NULL && --pstr->ref == 0)//不要依赖于指针
        {
            free(pstr);
        }
        pstr = NULL; 
    }
    String& operator=(const String& s);
    ostream& operator<<(ostream& out) const;

    char& operator[](const int index);
    const char& operator[](const int index) const;
};
int main()
{
    String s1("hxy");
    String s2(s1);
    String s3(s1);
    String s4(s2);
    // s1 s2 s3 s4全部都指向s1指向的空间

    return 0;
}

2.友元

外部函数友元,友元函数是一个外部函数,没有this指针,不能用const修饰。

class Object
{
private:
    int value;
public:
    Object(int x) :value(x) {}
    friend ostream& operator<<(ostream& out, const Object& obj);
};
ostream& operator<<(ostream& out, const Object& obj)
{
    out << obj.value;//外部对象友元:外部函数无法访问对象私有属性
    return out;
}
int main()
{
    Object obj(10);
    cout << obj << endl;
    return 0;
}

成员函数友元

class Object;
class Base
{
private:
    int sum;
public:
    Base(int x = 0) :sum(x) {}
    void fun(Object&);
};
class Object
{
private:
    int value;
public:
    Object(int x) :value(x) {}
    friend void Base::fun(Object& obj);
};
;
void Base::fun(Object& obj)
{
    obj.value = obj.value + sum;
}
int main()
{
    Base base(10);
    Object obja(20);
    base.fun(obja);
    
    return 0;
}

2.1特点

(1)友元不具有自反性
(2)友元不具有传递性
(3)友元不具有继承性

2.2类型

(1)函数友元
(2)类友元
(3)成员函数友元

举报

相关推荐

0 条评论