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;
}
#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.初始化列表
#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指针。
注意:友元函数可访问类的私有和保护成员,但不是类的成员函数 ;
#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;
}