友元,静态成员,模板函数,模板类型
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、值类别
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)成员函数友元