// 定义类
class CAnimal { // 类关键字 class,类名 CAnimal
public: // 成员访问控制符,public 表示对其他类可见
CAnimal(){} // 无参构造函数,创建类对象时自动调用,注意构造函数名即为类名,无返回值
~CAnimal(){} // 析构函数,类对象销毁时自动调用,注意析构函数名即为 ~类名,无返回值
void SetName(const std::string &name) { // 类成员函数
this->m_name = name; // m_name = name 也可以
}
private: // private 表示对其他类不可见
std::string m_name; // 类成员变量
}; // 注意结尾分号,class XXX {}; 这是一个空类,编译时自动创建无参构造和析构函数
int main () {
CAnimal animal; // 类对象声明(栈)
animal.SetName("cat"); // .(点),栈对象会引用对象调用类成员方式
CAnimal &refAnimal = animal;
refAnimal.SetName("cat2");
CAnimal *panimal = new CAnimal; // 类对象声明(堆或自由存储区)
panimal->SetName("dog"); // ->(箭头),指针对象调用类成员方式
delete panimal;
return 0;
}
void Print() {
std::cout << "Print()" << std::endl;
}
void Print(int, int) {
std::cout << "Print(int, int)" << std::endl;
}
void Print(int, double) {
std::cout << "Print(int, double)" << std::endl;
}
void Print(double, int) {
std::cout << "Print(double, int)" << std::endl;
}
int main(int argc, char *argv[])
{
// 函数重载规则
// 1. 函数名称相同
// 2. 函数形参不同(包括:形参数量、形参类型、形参排列顺序等)
// 3. 函数返回值不作为函数重载的判断依据
// 重载函数匹配规则
// 1. 精确匹配:无强制或隐式类型转换,数组做函数参数退化为指针等情况
// 2. 提升匹配:自动隐式转换(如bool 到 int、char到int、short 到int、int 到 double、float 到 double等等)
// 3. 强制转换调用某个重载函数
// 4. 无匹配函数
// 5. 注意函数参数设置,防止出现函数调用二义性(有多个满足条件的调用,编译器不知道调用哪个)
// 实际写的函数经过编译后函数名称根据情况,c++编译器会进行命名倾轧(即添加一些字符进行改变),不同重载函数最终在编译时也是不同的函数名称
// 运算符重载
// 1. c++中绝大多数运算符也可以重载,使用 operator 关键字,不能创建新运算符,重载需遵守运算符规则
// 2. 不能重载的运算符 .(成员运算符) .*(成员指针运算符) ::(作用域运算符) ?:(条件运算符) sizeof(sizeof运算符) typeid(一个RTTI运算符) 四个强制类型转换运算符
// 3. 重载运算符 () [] -> 或 = 时,只能重载为成员函数,不能重载为全局函数
Print();
Print(1, 1);
Print(1, 4.0);
Print(4.0, 1);
return 0;
}
输出结果:
Print()
Print(int, int)
Print(int, double)
Print(double, int)
class CAnimals {
public:
CAnimals()
: m_name("cat"){ // 无参构造,使用初始化列表赋值,这样比写在函数中初始化时间早,且 const 修饰的成员变量赋值不能写在函数中
std::cout << "CAnimals()" << std::endl;
}
CAnimals(const std::string &name)
: m_name(name){ // 有参构造
std::cout << "CAnimals(const std::string &name)" << std::endl;
}
CAnimals(const CAnimals& other) { // 拷贝复制构造,对象和对象之间的拷贝复制
this->m_name = other.m_name;
std::cout << "CAnimals(const CAnimals& other)" << std::endl;
}
CAnimals& operator = (const CAnimals& other) { // 对象间的赋值运算(对赋值运算符 = 重载)
if (this == &other) // 避免自赋值
return *this;
this->m_name = other.m_name;
std::cout << "CAnimals& operator = (const CAnimals& other)" << std::endl;
return *this;
}
~CAnimals() {
std::cout << "~CAnimals" << std::endl;
}
private:
std::string m_name; // std::string m_name = "";
};
int main(int argc, char *argv[])
{
std::cout << "Create object a: " << std::endl;
CAnimals a;
std::cout << "Create object b: " << std::endl;
CAnimals b("dog");
std::cout << "Create object c: " << std::endl;
CAnimals c(a);
std::cout << "Create object d: " << std::endl;
CAnimals d = b;
std::cout << "Create object e: " << std::endl;
CAnimals e;
e = d;
// 析构顺序为 e d c b a,与构造顺序相反
return 0;
}
输出结果:
Create object a:
CAnimals()
Create object b:
CAnimals(const std::string &name)
Create object c:
CAnimals(const CAnimals& other)
Create object d:
CAnimals(const CAnimals& other)
Create object e:
CAnimals()
CAnimals& operator = (const CAnimals& other)
~CAnimals
~CAnimals
~CAnimals
~CAnimals
~CAnimals
class CDemo; // 类前置声明
class CAnimals {
public:
void SetName(const std::string &name) {
m_name = name;
}
void Print(const CDemo &obj);
private:
friend void Print(const CAnimals& obj); // 友元函数声明
std::string m_name = "Cat";
friend CDemo; // 友元类声明
};
void Print(const CAnimals& obj) {
std::cout << "CAnimals Print: " << obj.m_name << std::endl;
}
class CDemo {
public:
void Print(const CAnimals& obj) {
std::cout << "CDemo Print: " << obj.m_name << std::endl;
}
friend void CAnimals::Print(const CDemo &obj); // 友元成员函数
friend std::ostream &operator << (std::ostream &os, const CDemo& obj); // 重载 << 运算符
private:
std::string m_name = "Dog";
};
std::ostream &operator << (std::ostream &os, const CDemo& obj) {
return (os << "operator <<: " << obj.m_name << '\t');
}
void CAnimals::Print(const CDemo &obj) {
std::cout << "CAnimals::Print: " << obj.m_name << std::endl;
}
int main(int argc, char *argv[])
{
CAnimals obj;
Print(obj);
CDemo demo;
demo.Print(obj);
obj.Print(demo);
std::cout << demo << "ok" << std::endl;
return 0;
}
输出结果:
CAnimals Print: Cat
CDemo Print: Cat
CAnimals::Print: Dog
operator <<: Dog ok
// 使用编译器创建的拷贝复制构造函数(浅拷贝)和赋值函数(浅拷贝),注意观察输出 address
class CAnimal {
public:
CAnimal()
: m_property(new char[11]){
for (int i = 0; i < 10; ++i)
m_property[i] = i + 97;
}
void Print() {
printf("address: %p\n", &m_property[0]);
for (int i = 0; i < 10; ++i)
std::cout << m_property[i] << "\t";
std::cout << std::endl;
}
private:
char *m_property = nullptr;
};
int main(int argc, char *argv[])
{
CAnimal a;
a.Print();
CAnimal b = a;
b.Print();
CAnimal c(a);
c.Print();
CAnimal d;
d = a;
d.Print();
return 0;
}
输出结果:
address: 0000000000fe17b0
a b c d e f g h i j
address: 0000000000fe17b0
a b c d e f g h i j
address: 0000000000fe17b0
a b c d e f g h i j
address: 0000000000fe17b0
a b c d e f g h i j
// class CAnimal 中添加拷贝复制构造函数(实现深拷贝),注意观察输出 address
CAnimal(const CAnimal& other) {
if (other.m_property == nullptr)
return;
if (this->m_property != nullptr)
delete [] this->m_property;
this->m_property = new char[strlen(other.m_property + 1)]; // 分配空间
strcpy(this->m_property, other.m_property); // 拷贝内容
}
输出结果:
address: 0000000000fb17b0
a b c d e f g h i j
address: 0000000000fb17d0
a b c d e f g h i j
address: 0000000000fb1b20
a b c d e f g h i j
address: 0000000000fb17b0
a b c d e f g h i j
// class CAnimal 中添加赋值函数(实现深拷贝),注意观察输出 address
CAnimal &operator = (const CAnimal& other) {
if (this == &other) // 判断自赋值
return *this;
if (this->m_property != nullptr) // 清空原内容
delete [] this->m_property;
this->m_property = new char[strlen(other.m_property + 1)]; // 分配空间
strcpy(this->m_property, other.m_property); // 拷贝内容
return *this;
}
输出结果:
address: 00000000006f17b0
a b c d e f g h i j
address: 00000000006f17d0
a b c d e f g h i j
address: 00000000006f1b20
a b c d e f g h i j
address: 00000000006f1b40
a b c d e f g h i j
class CMyString {
public:
CMyString() {}
CMyString(const char *data) {
if (!data)
return;
m_pdata = new char[strlen(data) + 1];
strcpy(m_pdata, data);
}
CMyString(const CMyString& other) {
if (other.m_pdata == nullptr)
return;
m_pdata = new char[strlen(other.m_pdata) + 1];
strcpy(m_pdata, other.m_pdata);
}
CMyString &operator=(const CMyString& other) {
if (this == &other || other.m_pdata == nullptr) // 此处编写时规则是 other.m_pdata 为空时,当前对象不改变,可修改
return *this;
if (m_pdata != nullptr)
delete [] m_pdata;
m_pdata = new char[strlen(other.m_pdata) + 1];
strcpy(m_pdata, other.m_pdata);
return *this;
}
CMyString operator + (const CMyString& other) { // 重载 + 运算符
if (other.m_pdata == nullptr)
return *this;
CMyString ret;
int len = strlen(this->m_pdata) + strlen(other.m_pdata) + 1;
char *p = new char[len];
strcpy(p, this->m_pdata);
strcpy(p + strlen(this->m_pdata), other.m_pdata);
ret = p;
delete [] p;
return ret;
}
char &operator [] (size_t index) { // 重载 [] 运算符
if (index < 0 || index >= strlen(m_pdata))
throw "over range";
return m_pdata[index];
}
~CMyString() { // 析构函数
if (m_pdata)
delete [] m_pdata;
}
void Print() { // 为打印方便,内置此打印函数
if (m_pdata == nullptr)
return;
int len = strlen(m_pdata);
for (int i = 0; i < len; ++i)
std::cout << m_pdata[i] << '\t';
std::cout << std::endl;
}
private:
char *m_pdata = nullptr;
};
int main(int argc, char *argv[])
{
CMyString a;
a = "HelloWorld"; // char * 类型初始化,调用 char * 类型构造函数
a.Print();
CMyString b("HelloWorld");
b.Print();
CMyString c = a;
c.Print();
CMyString d;
d = b;
d.Print();
CMyString e = (d + b);
e.Print();
std::cout << "e[0]: " << e[0] << std::endl;
e[0] = 'S'; // 修改值
e.Print();
return 0;
}
输出结果:
H e l l o W o r l d
H e l l o W o r l d
H e l l o W o r l d
H e l l o W o r l d
H e l l o W o r l d H e l l o W o r l d
e[0]: H
S e l l o W o r l d H e l l o W o r l d
class CStatic {
public:
static int m_id; // 静态成员变量声明
static int GetId () { // 只能访问 static 修饰的内容
return m_id;
}
};
int CStatic::m_id = 10; // 类内声明(一般在 .h 文件)、类外初始化(一般在 .cpp文件)
int main(int argc, char *argv[])
{
// 静态成员变量和静态成员函数调用方式,属于类而不属于某个对象,所以使用 类名::静态内容
std::cout << "Get id: " << CStatic::m_id << std::endl;
std::cout << "Get id: " << CStatic::GetId() << std::endl;
}
输出结果:
Get id: 10
Get id: 10