0、多态 封装 继承
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

多态的三个条件:

  1. 继承的存在
  2. 子类重写父类的方法
  3. 父类引用变量指向子类对象

封装:封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

继承:继承主要实现重用代码,节省开发时间

// 面向对象的五大基本原则
单一职责原则(SRP)
开放封闭原则(OCP)
里氏替换原则(LSP)
依赖倒置原则(DIP)
接口隔离原则(ISP)

一、返回值
C中:如果函数未指定返回值类型,则默认为int
c++中:如果一个函数没有返回值,返回值类型必须指定为void
二、参数列表
C中:如果函数没有指定参数列表,则默认可以接受任意多个参数
C++中:有严格的类型检测,没有参数列表的函数默认为void,不接受任意参数
三、缺省参数(即给参数一个默认值)
C:不支持
C++:支持(如果没有指定实参则使用缺省值,有则使用指定实参)
1.默认实参必须在参数列表的结尾
2.默认参数只能出现在函数声明或者定义二选一中
3.缺省值必须是常量或全局变量
4.缺省参数必须是值传递或者常参传递
四、函数重载
C:不支持
C++:支持在同一作用域中存在几个功能类似的同名函数,但参数列表(参数个数、类型、顺序)不同
五、引用和指针
引用:可以看做是一个变量的别名
特点:1.必须初始化
2.一个变量可以有多个引用
3.引用一旦初始化,就不能在成为其他变量的引用
ps:数组不能被引用
引用与指针的异同:
同:底层实现相同
异:1.引用必须初始化
2.引用一旦绑定就不能更改
3.++的结果不同
4.有多级指针,没有多级引用

多态 封装 继承

2、const和const_cast强制转换
符号表 只读
// 字面量初始化的const常量进入符号表
// 其他变量初始化的const常量只读变量
int main(void)
{
const int a = 7;// 每次直接从符号表读取,而不是内存读取,但是也分配内存
// 加入volatile修饰时,编译器不做优化,从内存地址读取数据
int *b = (int *)&a;

*b = 100;

printf("%d\n", a);	 // 7	进入符号表,值不会变

}

// volatile修饰的const常量不会进入符号表
// 在extern和&修饰的const常量时,会分配空间,但是不会去使用
int main()
{
const int x = 1;// 进入符号表
const int& rx = x;// 常量引用
int& nrx = const_cast<int&>(rx);// 去除只读属性

nrx = 5;

printf("x = %d\n", x);		// 1
printf("rx = %d\n", rx);		// 5
printf("nrx = %d\n", nrx);	// 5

printf("x = %p\n", &x);		// 0xaabbccdd
printf("x = %p\n", &rx);		// 0xaabbccdd
printf("x = %p\n", &nrx);	// 0xaabbccdd

/////////////////////////////////////////////
volatile const int y = 2;		// 没进入符号表
int* py = const_cast<int*>(&y);

*py = 5;

printf("y = %d\n", y);		// 5
printf("py = %p\n", &py);	// 0xasdfghj

////////////////////////////////////////////
const int z = y;			// y 是不确定的变量,所以z是只读变量
py = const_cast<int*>(&z);	// 去除只读属性

*py = 5;

printf("y = %d\n", z);		// 5
printf("py = %p\n", &py);	// 0xasdfghj

/////////////////////////////////////////////
char c = 'c';
char& rc = c;
const int& trc = c;			// 不同类型间的常量引用分配新的空间

rc = 'a';

printf("c = %c\n", c);		// a
printf("rc = %c\n", rc);		// a
printf("trc = %c\n", trc);		// c

printf("c = %p\n", &c);		// 0xaabbccdd
printf("rc = %p\n", &rc);		// 0xaabbccdd
printf("trc = %p\n", &trc);	// 0xaabbdcda

return 0;

}

// 区别于C++,C语言中const修饰的变量本质上还是变量,其值只有在运行时才能确定
// #define 被预编译处理,没有作用域的概念
// const有作用域和类型检查
void f()
{
#define a 3// 宏使被预处理的 直接文本替换
const int b = 4;// const作用域只在此函数中
}

void g()
{
printf(“a = %d\n”, a);//
//printf(“b = %d\n”, b);// error
}

int main()
{
const int A = 1;// 常量被编译进符号表
const int B = 2;
int array[A + B] = {0};
int i = 0;

for(i=0; i<(A + B); i++)
{
    printf("array[%d] = %d\n", i, array[i]);
}

f();
g();

return 0;

}

// const修饰的对象为只读对象,只能调用const的成员函数,其成员变量不能直接被修改

3、三目运算
// C++三目运算可以返回a或b的引用,可以当左值。但是其中有常量时,不能当左值
int a = 1;
int b = 2;

( a<b ? a : b) = 3;// ok
( a<b ? 1 : b) = 3;// error

4、引用和const引用(常量引用)
// 引用在初始化的时候必须进行初始化,类型要一致
int main(int argc, char *argv[])
{
int a = 4;
int& b = a; // b是a的别名

b = 5;

printf("a = %d\n", a);		// 5
printf("b = %d\n", b);		// 5
printf("&a = %p\n", &a);	// 0xaabbccdd
printf("&b = %p\n", &b);	// 0xaabbccdd

return 0;

}

// const引用可以用常量初始化,但非const引用不能用常量初始化。
const int &ir = 10;
int &jr = 10; // error

// 只有const引用才能被临时变量或临时对象初始化
// 另一个由于对象的调用会自动调用构造函数,对象的引用可以提高效率
void print(string& str)
{
cout<<str<<endl;
}
print(“hello world”); // 如此调用会报错误

出错的原因是编译器根据字符串”hello world”构造一个string类型的临时对象,这个临时对象具有const属性。当这个临时对象传递给非const的string&引用类型时,因为非const引用绑定对象时,要求该对象也是非const对象。而在这时,因为string类型的临时对象是const对象,所以就出现错误。因此,解决办法就是将print()函数的参数改为常引用。代码修改如下,可顺利通过编译。
void print(const string& str)
{
cout<<str<<endl;
}
print(“hello world”);// 顺利通过编译

// const引用不能被用于修改其绑定的对象,其值拥有只读属性
void Example()
{
int a = 4;

const int& b = a;// b拥有只读属性
int* p = (int*)&b;

//b = 5; // error
*p = 5;

printf("a = %d\n", a);	// 5
printf("b = %d\n", b);	// 5

}

void Demo()
{
const int& c = 1;
int* p = (int*)&c;

//c = 5; // error
*p = 5;

printf("c = %d\n", c);	// 5

}

int main(int argc, char *argv[])
{
Example();
Demo();

return 0;

}

// 引用的实现是一个指针常量

struct TRef
{
char& r;
};

int main(int argc, char *argv[])
{
char c = ‘c’;
char& rc = c;//rc c
TRef ref = { c }; // rc

printf("sizeof(char&) = %d\n", sizeof(char&));	// 1
printf("sizeof(rc) = %d\n", sizeof(rc));			// 1

printf("sizeof(TRef) = %d\n", sizeof(TRef));	// 4 本质是指针
printf("sizeof(ref.r) = %d\n", sizeof(ref.r));	// 1

return 0;

}

// 引用不能够完全避免内存操作的失误
int& demo()
{
int d = 0;

printf("demo: d = %d\n", d);

return d; // 不能返回局部变量的引用

}

int& func()
{
static int s = 0;// 拥有全局生命周期,但制作用于局部变量

printf("func: s = %d\n", s);

return s;

}

int main(int argc, char* argv[])
{
int& rd = demo();// 0
int& rs = func();// 0

printf("\n");
printf("main: rd = %d\n", rd);		// 11223344 代表的是一个不存在的变量
printf("main: rs = %d\n", rs);		// 0
printf("\n");

rd = 10;
rs = 11;

demo();	// 0
func();	// 11

printf("\n");
printf("main: rd = %d\n", rd);	// 11223344 已经不存在
printf("main: rs = %d\n", rs);	// 11
printf("\n");

return 0;

}

4、内联函数
// 内联函数省去函数调用时的压栈,跳转,和返回的开销,编译器会把该函数的代码副本放置在每个调用函数的地方
// inline只是一种请求,编译器你可以拒绝
•1.在内联函数内不允许使用循环语句和开关语句;
•2.内联函数的定义必须出现在内联函数第一次调用之前;
•3.类结构中所在的类说明内部定义的函数是内联函数。

#define FUNC(a, b) ((a) < (b) ? (a) : (b))

inline int func(int a, int b)
{
return a < b ? a : b;
}

int main(int argc, char *argv[])
{
int a = 1;
int b = 3;
int c = FUNC(++a, b);

printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);

return 0;

}

// VC的强制内敛 __forceinline
// g++的强制内敛 attribute((always_inline))
// C++的强制内敛 inline

//__forceinline
//attribute((always_inline))
//inline

int add_inline(int n);

int main(int argc, char *argv[])
{
int r = add_inline(10);

printf(" r = %d\n", r);

return 0;

}

inline int add_inline(int n)
{
int ret = 0;

for(int i=0; i<n; i++)
{
    ret += i;
}

return ret;

}
5、函数参数的扩展
// 函数参数可以提供默认值
// 默认参数可以在定义时或者声明时指定,提供的参数在被调用时要被看见。
int mul(int x = 0);

int main(int argc, char *argv[])
{
printf("%d\n", mul());// 0
printf("%d\n", mul(-1));// 1
printf("%d\n", mul(2));// 4

return 0;

}

int mul(int x)
{
return x * x;
}
// 参数的默认值从右向左提供
// 参数的调用从左向右

int add(int x, int y = 0, int z = 0);

int main(int argc, char *argv[])
{
printf("%d\n", add(1)); // 1
printf("%d\n", add(1, 2));// 3
printf("%d\n", add(1, 2, 3));// 6
printf("%d\n", add(1, , ));// 6
printf("%d\n", add( , 2, 3));// error x默认 y z没有默认

return 0;

}

int add(int x, int y, int z)
{
return x + y + z;
}
//为了兼容C语言,定义时可以用占位参数,一般不使用占位参数

int func(int x, int = 0);

int main(int argc, char *argv[])
{
printf("%d\n", func(1));
printf("%d\n", func(2, 3));

return 0;

}

int func(int x, int)// 占位
{
return x;
}
6、重载
// 用同一个函数名定义不同的函数
// 参数个数不同 参数类型不同 参数顺序不同 之一
#include <stdio.h>
#include <string.h>

int func(int x)
{
return x;
}

int func(int a, int b)
{
return a + b;
}

int func(const char* s)
{
return strlen(s);
}

int main(int argc, char *argv[])
{
printf("%d\n", func(3));
printf("%d\n", func(4, 5));
printf("%d\n", func(“D.T.Software”));

return 0;

}

// 函数默认参数和函数重组
int func(int a, int b, int c = 0)
{
return a * b * c;
}

int func(int a, int b)
{
return a + b;
}

int main(int argc, char *argv[])
{
int c = func(1, 2); // error

return 0;

}

// 函数重载本质是相互独立的不同函数
int add(int a, int b) // int(int, int)
{
return a + b;
}

int add(int a, int b, int c) // int(int, int, int)
{
return a + b + c;
}

int main()
{
printf("%p\n", (int()(int, int))add);
printf("%p\n", (int(
)(int, int, int))add);

return 0;

}
// 函数重载和函数指针
int func(int x)
{
return x;
}

int func(int a, int b)
{
return a + b;
}

int func(const char* s)
{
return strlen(s);
}

typedef int(*PFUNC)(int a);// 函数指针

int main(int argc, char *argv[])
{
int c = 0;

PFUNC p = func;

c = p(1);

printf("c = %d\n", c);

return 0;

}

///////////////////////////////
#ifdef __cplusplus
extern “C” {
#endif
//////////////
#include “add.h”
//////////////
#ifdef __cplusplus
}
#endif

int main()
{
int c = add(1, 2);

printf("c = %d\n", c);

return 0;

}
7、动态内存分配 命名空间
// 分配空间时可以初始化
// int* p = new int(); delete p;
// p = new int[10]; delete[] p;
int main()
{
int* p = new int;

*p = 5;
*p = *p + 10;

printf("p = %p\n", p);
printf("*p = %d\n", *p);

delete p;

p = new int[10];

for(int i=0; i<10; i++)
{
    p[i] = i + 1;

    printf("p[%d] = %d\n", i, p[i]);
}

delete[] p;

return 0;

}

// 命名空间解决全局变量冲突的问题
namespace First
{
int i = 0;
}

namespace Second
{
int i = 1;

namespace Internal
{
    struct P
    {
        int x;
        int y;
    };
}

}

int main()
{
using namespace First;
using Second::Internal:😛;

printf("First::i = %d\n", i);
printf("Second::i = %d\n", Second::i);

P p = {2, 3};

printf("p.x = %d\n", p.x);
printf("p.y = %d\n", p.y);

return 0;

}

8、强制类型转换
static_cast(expression)
// static_cast:用于基本类型转换,不能用于基本类型的指针转换,用于继承关系对象的转换和类指针的转换
// const_cast:去除变量的只读属性,用于指针或引用
// dynamic_cast :用于继承关系的类指针转换,用于有交叉关系的类指针的转换,具
有类型检查功能,需要虚函数支持
// reinterpret_cast:用于指针间转换,用于整数和指针见的转换

void static_cast_demo()
{
int i = 0x12345;
char c = ‘c’;
int* pi = &i;
char* pc = &c;

c = static_cast<char>(i);	// 基本类型转换
pc = static_cast<char*>(pi);	// 基本指针类型转换

}

void const_cast_demo()
{
const int& j = 1;// 只读变量
int& k = const_cast<int&>(j);// 去除只读属性

const int x = 2;				// 进入了符号表
int& y = const_cast<int&>(x);	//没去除只读属性,重新分配去除只读属性的变量空间

int z = const_cast<int>(x);		// error 只用于引用和指针

k = 5;

printf("k = %d\n", k);	// 5
printf("j = %d\n", j);		// 5

y = 8;

printf("x = %d\n", x);	// 2
printf("y = %d\n", y);	// 8
printf("&x = %p\n", &x);	// 0xaabbccdd
printf("&y = %p\n", &y);	// 0xaabbccdd

}

void reinterpret_cast_demo()
{
int i = 0;
char c = ‘c’;
int* pi = &i;
char* pc = &c;

pc = reinterpret_cast<char*>(pi);	// 指针间的转换
pi = reinterpret_cast<int*>(pc);
pi = reinterpret_cast<int*>(i);		// 指针和整形间的转换
c = reinterpret_cast<char>(i); 		// error

}

void dynamic_cast_demo()
{
int i = 0;
int* pi = &i;
char* pc = dynamic_cast<char*>(pi);// error 需要虚函数支持的类函数之间的转换
}

int main()
{
static_cast_demo();
const_cast_demo();
reinterpret_cast_demo();
dynamic_cast_demo();

return 0;

}
9、类与封装
// 类成员的访问
int i = 1;

struct Test
{
private:
int i;

public:
int j;

int getI()
{
	i = 3;

	return i;
}

};

int main()
{
int i = 2;

Test test;

test.j = 4;

printf("i = %d\n", i);				// 2
printf("::i = %d\n", ::i);         	// 1 全局作用域
printf("test.i = %d\n", test.i); 	// Error  私有变量
printf("test.j = %d\n", test.j);    	// 4
printf("test.getI() = %d\n", test.getI());  // test.getI() = 3

return 0;

}

11、类的成员 - 构造函数
// 构造函数的作用是对对象自动初始化
// 构造函数与类名相同,没有返回值,在对象定义时自动被调用
// 栈和堆上创建对象时,成员变量初始值为随机值
// 静态储存区和全局区上创建对象时,成员变量初始值为0
// 不能为虚函数,虚函数是为了对象的动态调用,对象都没构造,哪来的虚函数。
class Test
{
private:
int i;
int j;

public:
int getI() { return i; }
int getJ() { return j; }
Test()// 构造函数
{
i = 1;
j = 1;
}
};

Test gt;// 全局区对象

int main()
{
printf(“gt.i = %d\n”, gt.getI());// 全局数据区统一为0
printf(“gt.j = %d\n”, gt.getJ());

Test t1;						// 栈区对象
printf("t1.i = %d\n", t1.getI());	// 栈空间初始值不定
printf("t1.j = %d\n", t1.getJ());

Test* pt = new Test;			 // 堆区对象
printf("pt->i = %d\n", pt->getI()); // 堆空间初始值不定
printf("pt->j = %d\n", pt->getJ());

delete pt;

return 0;

}

// 带有参数的构造函数,满足重载规律
class Test
{
public:
Test()
{
printf(“Test()\n”);
}
Test(int v)
{
printf(“Test(int v), v = %d\n”, v);
}
};

int main()
{
Test t; // 调用 Test()
Test t1(1); // 调用 Test(int v)
Test t2 = 2; // 调用 Test(int v)

int i(100);

printf("i = %d\n", i);

return 0;

}

11、类的成员 - 初始化列表
必须在类初始化列表中初始化的几种情况:

  1. 类成员为const或引用类型
  2. 类成员为类类型
  3. 子类调用父类构造函数

// 1.const和引用只能初始化不能赋值
class Base
{
private:
const int i;// const
int &j;// 引用

public:
Base(int v) : i(v), j(v) // 用列表初始化
{
}
void print_val()
{
cout << i << " " << j << endl;
}
};

int main(int argc ,char **argv)
{
Base b(100);

b.print_val();

}

// 2.通过显式调用父类构造函数,对父类数据成员初始化

#include <stdio.h>
#include
#include

using namespace std;
class Base
{
private:
int x;
int y;
int z;
public:
Base (int a, int b, int c)
{
cout << “Base” << a << " " << b << " " << c << endl;
};
};

class MyBase
{
private:
Base b; // 类类型
public:
MyBase(): b(1,2,3)// 列表初始化父类数据成员
{
cout << “MyBase” << endl;
};
};
int main()
{
MyBase b;// 1 2 3
// MyBase
return 0;
}

// 3. 如果类存在继承关系,子类必须在其初始化列表中调用父类的构造函数
class Base
{
private:
int a;

public:
Base(int a)
{
cout << “Base” << a << endl;
}
};
class Mybase : public Base// 继承关系
{
private:
int b;

public:
Mybase(int v) : Base(v) // 子类调用父类构造函数
{
b = v;
cout << “MyBase” << endl;
}
};

int main(int argc ,char **argv)
{
Mybase mybase(100); // 100
// MyBase
return 0;
}

// 成员的初始化顺序和声明顺序相同
// 初始化列表先于构造函数执行
class Value
{
private:
int mi;
public:
Value(int i)
{
printf("i = %d ", i);
}
};

class Test
{
private:// 声明顺序
Value m2;// 类类型
Value m3;
Value m1;

public:
Test() : m1(1), m2(2), m3(3) // 初始化列表
{
printf(“Test::Test()\n”);
}
};

int main()
{
Test t; // i = 2 i = 3 i = 1
// Test::Test()
return 0;
}

11、类的成员 - 拷贝构造函数
C++中三种情况下需要调用拷贝构造函数:

  1. 对象以值传递的方式传入函数参数
  2. 对象以值传递的方式从函数返回
  3. 一个对象用于初始化另一个对象

// 1.值传递给函数时会产生临时变量作为拷贝构造函数的实参
class CExample
{
private:
int a;
public:
CExample(int b)
{
a = b;
cout<<"creat: "<<a<<endl;
}
CExample(const CExample& C)
{
a = C.a;
cout<<“copy”<<endl;
}
~CExample()
{
cout<< "delete: "<<a<<endl;
}
void Show ()
{
cout<<a<<endl;
}
};

void g_Fun(CExample C) // 这里如果改成CExample& C引用就不会产出临时变量
{
cout<<“test”<<endl;
}

int main()
{
CExample test(11); // creat: 11
g_Fun(test); // copy
test
// delete: 11 这里两次调用析构,一次是析构临时变量
// delete: 11 一次析构对象
return 0;
}

// 2.返回对象时产生一个临时对象作为拷贝构造函数的实参
class Integer
{
public:
int m_val;

Integer()
{
     cout<<"default Constructor"<<endl;
};
Integer(int i):m_val(i)
{
    cout<<"Constructor"<<endl;
};
Integer(const Integer& arg)
{
    this->m_val=arg.m_val;
    cout<<"Copy Constructor"<<endl;
};
~Integer()
{
	cout << "delete" << endl;
};

};

Integer testFunc(Integer inter)
{
inter.m_val++;
cout<<“before return”<<endl;
return inter;
}

int main(int argc,char* argv[])
{
Integer resutl; // default constructor 对象构造

resutl = testFunc(2);	    // Constructor  	 形参对象的构造                	\
						  before return	 进入函数		              	\
					      Copy Constructor返回临时对象,调用拷贝构造函数	\							  delete	析构掉临时对象                         	\
						  delete 析构掉参数对象
cout<<resutl.m_val<<endl; // 3
						// delete 析构掉resutl对象
return 0;

}

// 3.对象需要通过另外一个对象进行初始化
CExample A(100);
CExample B = A;

// 浅拷贝 深拷贝
// 没定义构造函数时,编译器自动提供无参构造函数和拷贝构造函数(有拷贝操作时)
// 自定义构造函数的话,两个构造函数必须同时指定
// 自定义构造函数,必然需要实现深拷贝

// 拷贝构造函数必须用引用传值,也就是传址,因为传址会造成再次调用构造函数,形成死循环

// 当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象

class Test
{
private:
int i;
int j;
int* p;

public:
int getI()
{
return i;
}
int getJ()
{
return j;
}
int* getP()
{
return p;
}
Test(int v)// 构造函数
{
i = 1;
j = 2;
p = new int;

    *p = v;
}
Test(const Test& t)	// 深拷贝构造函数
{
    i = t.i;
    j = t.j;
    p = new int;

    *p = *t.p;
}
void free()
{
    delete p;
}

};

int main()
{
Test t1(3);
Test t2(t1);

printf("t1.i = %d, t1.j = %d, *t1.p = %d\n", t1.getI(), t1.getJ(), *t1.getP());
printf("t2.i = %d, t2.j = %d, *t2.p = %d\n", t2.getI(), t2.getJ(), *t2.getP());

t1.free();
t2.free();

return 0;

}

12、类的成员 - 析构函数
// 用来销毁对象,没有参数 没有返回值 被自动调用
// 析构顺序由于全局、静态变量先于局部变量构造,首先析构局部变量,而手动析构在 } 之前,在由于全局变量作用域大于静态变量,先于静态变量构造,所以最后析构

class Test
{
private:
int mi;

public:
Test(int i)
{
mi = i;
printf(“Test(): %d\n”, mi);
}
~Test()
{
printf("~Test(): %d\n", mi);
}
};

Test C(1);
int main()
{
Test* A = new Test(4);
static Test D(2);
Test B(3);

delete A;		// ~Test(): 4   \
			  ~Test(): 3   \
			  ~Test(): 2   \
			  ~Test(): 1	 \
return 0;

}

class Member
{
const char* ms;
public:
Member(const char* s)
{
printf(“Member(const char* s): %s\n”, s);

    ms = s;
}
~Member()
{
    printf("~Member(): %s\n", ms);
}

};

class Test
{
Member mA;
Member mB;
public:
Test() : mB(“mB”), mA(“mA”)
{
printf(“Test()\n”);
}
~Test()
{
printf("~Test()\n");
}
};

Member gA(“gA”);

int main()
{
Test t;

return 0;

}

13、类的成员 - 临时对象
临时对象产生主要有以下三种情况:

  1. 以值的方式给函数传参
  2. 函数返回一个对象时
  3. 隐式类型转换

// 值传递时会调用拷贝构造函数,并且创建临时对象;在多次继承情况下,临时对象的创建是一个很大的性能消耗,用引用传参可以避免

// 1.值传递给函数参数首先会产生临时变量,其次调用拷贝构造函数传递临时变量,然后临时变量进入函数进行相关操作,最后析构掉临时对象和对象
class CTemp
{
public:
int a;
int b;
public:
CTemp(int m, int n);
CTemp(const CTemp& t);
int GetSum(CTemp ts);
};

CTemp::CTemp(int m , int n)
{
printf(“Construct function!\n”);
a = m;
b = n;
printf(“a = %d, b = %d\n”,a,b);
}

CTemp::CTemp(const CTemp& t)
{
printf(“Copy function!\n”);
a = t.a;
b = t.b;
}

CTemp:: ~CTemp()
{
printf(“delete!\n”);
}

int CTemp::GetSum(CTemp ts)// 修改成CTemp& ts
{
int tmp = ts.a + ts.b;
ts.a = 1000; //此时修改的是tm的一个副本

return tmp;

}

int main()
{
CTemp tm(10,20);// Construct function! 调用构造函数
a = 10, b = 20
printf(“Sum = %d \n”,tm.GetSum™);// Copy function! 调用拷贝构造函数
Sum = 30
delete! 这里是析构临时变量
printf(“tm.a = %d \n”,tm.a);// tm.a = 10修改成引用tm.a = 1000
delete!
}

// 2.返回对象时产生一个临时对象作为拷贝构造函数的实参
class Integer
{
public:
int m_val;

Integer()
{
     cout<<"default Constructor"<<endl;
};
Integer(const Integer& arg)
{
    this->m_val=arg.m_val;
    cout<<"Copy Constructor"<<endl;
};
~Integer()
{
	cout << "delete" << endl;
};

};

Integer testFunc( )
{
Integer inter;
cout<<“before return”<<endl;
return inter;
}

int main(int argc,char* argv[])
{
testFunc(); // default constructor
before return
delete析构掉临时对象
return 0;
}

// 3.隐式类型转换生成临时对象
void print(string& str)
{
cout<<str<<endl;
}
print(“hello world”); // 如此调用会报错误

11、类的成员 – 虚函数和纯虚函数
// 虚函数可以被直接使用,也可以被子类重载后以多态形式调用
// 纯虚函数在子类中只有声明而没有定义,必须在子类中实现该函数,也可以在子类中重载,以多态形式被调用
class test
{
virtual string toString() = 0;// 纯虚函数
};

struct child:test
{
string toString() // 在子类中实现
{
return “ccc”;
}
};

struct sun:child
{
string toString()
{
return “sss”;
}
};

int main()
{
sun s;
child* c;

c = &s;

cout<<c->toString()<<endl; // sss

return 0;

}

14、类的成员 - 静态成员变量
// static成员变量是在类加载的时候生成
// 一般的成员变量是每个对象所自己拥有的,每次构造都会自己调用自己的成员变量
class Test
{
private:
int mCount;

public:
Test() : mCount(0)
{
mCount++;
}
~Test()
{
–mCount;
}
int getCount()
{
return mCount;
}
};

Test gTest;

int main()
{
Test t1;
Test t2;

printf("count = %d\n", gTest.getCount());	// 1
printf("count = %d\n", t1.getCount());		// 1
printf("count = %d\n", t2.getCount());		// 1

return 0;

}

// 实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存
// static静态成员变量属于整个类所有,先于对象存在,可以类名::变量直接访问
不隶属于任何一个单独的对象
需要在类外单独分配空间
储存在全局数据区
class Test
{
private:
static int cCount;// 不隶属于任何对象

public:
Test()
{
cCount++;
}
~Test()
{
–cCount;
}
int getCount()
{
return cCount;
}
};

int Test::cCount = 0;// 在类的外部单独定义,为其分配空间

Test gTest;

int main()
{
Test t1;
Test t2;

printf("count = %d\n", gTest.getCount());	// 3		统计某个类的对象数目
printf("count = %d\n", t1.getCount());		// 3
printf("count = %d\n", t2.getCount());		// 3

Test* pt = new Test();	// pt指向一个动态分配的,并初始化的无名对象
printf("count = %d\n", pt->getCount());	// 4

delete pt;
printf("count = %d\n", gTest.getCount());	// 3

return 0;

}

15、类的成员 - 静态成员函数

由于static修饰的类成员属于类,不属于对象。
因此static类成员函数是没有this指针的,this指针是指向本对象的指针。
正因为没有this指针,所以static类成员函数不能访问非static的类成员,只能访问 static修饰的类成员
class Text
{
public:
static int fun()
{
return num;
}
static int count;
int num;
};
int Text::count=5;// 用static成员变量必须要初始化

int main()
{
Text t1;
Text t2;
t1.num=100;

t1.fun();	//发生错误,fun函数return的是非static类成员 如果return count就正确

return 0;
}

// 静态成员函数不可以直接访问成员变量
// 可以通过类名直接调用静态函数
// static静态成员变量属于整个类所有,先于对象存在,可以类名::变量直接访问
class Test
{
private:
int a;

public:
Test():a(0)
{
}
int getData();
static void setData(Test& T, int i); // 静态成员函数不可以直接访问成员变量
};

int Test::getData()
{
return a;
}

void Test::setData(Test& T, int i)
{
T.a = i;
}

int main()
{
Test T;

printf("%d\n", T.getData());

T.setData(T, 2);	// 可以通过类名
Test::setData(T, 2);	// 可以通过类名直接调用静态函数

printf("%d\n", T.getData());

return 0;

}

16、二阶构造模式
一、关于构造函数

  1. 类的构造函数用于对象的初始化
  2. 构造函数与类文明相同,且没有返回值
  3. 构造函数在对象被创建时自动被调用
    二、问题
    1.如何判断构造函数的执行结果?
    2.在构造函数中执行return语句会发生什么?
    3.构造函数执行结束意味着对象构造成功?

// 第一阶段:资源无关的初始化的操作
// 第二阶段:需要使用系统资源的操作
class TwoPhaseCons
{
private:
TwoPhaseCons() // 第一阶段构造函数
{
}
bool construct() // 第二阶段构造函数
{
return true;
}
public:
static TwoPhaseCons* NewInstance(); // 对象创建函数
};

TwoPhaseCons* TwoPhaseCons::NewInstance()
{
TwoPhaseCons* ret = new TwoPhaseCons();

if( !(ret && ret->construct()) ) // 若第二阶段构造失败,返回 NULL
{
    delete ret;
    ret = NULL;
}

return ret;

}

int main()
{
TwoPhaseCons* obj = TwoPhaseCons::NewInstance();// 只能被内部自动调用

printf("obj = %p\n", obj);

delete obj;

return 0;

}

//
#include “IntArray.h”
#include <stdio.h>

IntArray::IntArray()//1.
{

}
bool IntArray::IntArrayConstruct()//2.
{
m_Array = new int[5];

for(int i=0; i<5; i++)
{
m_Array[i] = 0;
}
return true;

}

IntArray* IntArray::NewIntArray()//3.
{
IntArray* ret = new IntArray();

if(!(ret && ret->IntArrayConstruct()))
{
delete ret;
ret = 0;
}
return ret;

}

bool IntArray::setArray(int index, int value)
{

if( (0 <= index) && (index < 5) )
    m_Array[index] = value;

return 0;

}

bool IntArray::getArray()
{
for(int i=0; i<5; i++)
{
printf("%d\n",*(m_Array+i));
}
return 0;
}

IntArray::~IntArray()
{
delete []m_Array;
}
////////////////////
#ifndef INTARRAY_H
#define INTARRAY_H

class IntArray
{
private:
int* m_Array;

IntArray();
bool IntArrayConstruct();

// ~IntArray();

public:
static IntArray* NewIntArray();
bool setArray(int index, int value);
bool getArray();
~IntArray();
};
#endif

//////////////////
#include <stdio.h>
#include “IntArray.h”
int main()
{
IntArray* A = IntArray::NewIntArray();

A->setArray(3, 22);
A->getArray();

delete A;

return 0;

}
17、友元函数
// 友元函数可以直接访问类的所有成员
// 破坏了C++的封装性
#include <stdio.h>
#include <math.h>

class Point
{
private:
double x;
double y;

public:
Point(double x, double y)
{
this->x = x;
this->y = y;
}

double getX()
{
    return x;
}

double getY()
{
    return y;
}

friend double func(Point& p11, Point& p22);

};

double func(Point& p11, Point& p22) // 全局函数
{
double ret = 0;

ret = (p22. getY() - p11. getY()) * (p22. getY() - p11 getY()y) +
      (p22. getX() - p11. getX()) * (p22. getX() - p11. getX());

ret = (p22.y - p11.y) * (p22.y - p11.y) +	// 直接调用
      (p22.x - p11.x) * (p22.x - p11.x);

ret = sqrt(ret);

return ret;

}

int main()
{
Point p1(1, 2);
Point p2(10, 20);

printf("p1(%f, %f)\n", p1.getX(), p1.getY());

printf(“p2(%f, %f)\n”, p2.getX(), p2.getY());

printf("|(p1, p2)| = %f\n", func(p1, p2));

return 0;

}
18、重载 - 类中函数的重载
// 类中的成员函数都可以重载(构造函数 普通成员函数 静态成员函数)
class Test
{
int i;
public:
/构造函数重载********/
Test()
{
printf(“Test::Test()\n”);
this->i = 0;
}
Test(int i)
{
printf(“Test::Test(int i)\n”);
this->i = i;
}
Test(const Test& obj)
{
printf(“Test(const Test& obj)\n”);
this->i = obj.i;
}
/静态成员函数重载********/
static void func()
{
printf(“void Test::func()\n”);
}

void func(int i)
{
    printf("void Test::func(int i), i = %d\n", i);
}

int getI()
{
    return i;
}

};
/普通函数重载********/
void func()
{
printf(“void func()\n”);
}
void func(int i)
{
printf(“void func(int i), i = %d\n”, i);
}

int main()
{
Test t; // Test::Test()
Test t1(1); // Test::Test(int i)
Test t2(t1); // Test(const Test& obj)
cout<<endl;

t1.func(); // void Test::func()
t1.func(2); // void Test::func(int i), i = 2
cout<<endl;

func();
func(1);

return 0;

}

// 重载函数可以扩展其功能
char* strcpy(char* buf, const char* str, unsigned int n)
{
return strncpy(buf, str, n);
}

int main()
{
const char* s = “D.T.Software”;
char buf[8] = {0};

//strcpy(buf, s);
strcpy(buf, s, sizeof(buf)-1);

printf("%s\n", buf);

return 0;

}
19、重载 – 运算符的重载
// 运算符重载的本质是一个函数
// 两个数相加相当于调用下面的函数:
int operator + (int a, int b) // 返回值为int类型
{return (a+b)}

///////////////////////////Complex.h///////////////////////////
#ifndefCOMPLEX_H
#defineCOMPLEX_H

class Complex
{
private:
int a;
int b;
public:
int getA();
int getB();
Complex(int, int) // 这里为什么必须要初始化a b
friend Complex operator + (const Complex& p1, const Complex& p2);
};
#endif
///////////////////////////Complex.cpp///////////////////////////
#include <stdio.h>
#include “Complex.h”

Complex(int a = 0, int b = 0) // 这里为什么必须要初始化a b
{
this->a = a;
this->b = b;
}

int Complex::getA()
{
return a;
}

int Complex::getB()
{
return b;
}

Complex operator + (const Complex& p1, const Complex& p2) // 全局的成员函数
{
int a = p1.a + p2.a;
int b = p1.b + p2.b;

return Complex(a, b);

}

///////////////////////////main.cpp/////////////////////////////
#include <stdio.h>
#include “Complex.h”
int main()
{
Complex c1(1, 2);
Complex c2(3, 4);
Complex c3 = c1 + c2;
printf(“c3.a = %d, c3.b = %d\n”, c3.getA(), c3.getB());

return 0;

}

// 操作数函数也可以通过成员函数来完成
// 当全局函数和成员函数同时存在时 优先调用成员函数
// 二元运算符成员函数重载时, 只需要一个参数, 另一个参数由this(左操作数)指针传入
#include <stdio.h>
#include
#include

using namespace std;

class Complex
{
private:
int a;
int b;

public:
Complex(int , int);
int getA();
int getB();
Complex operator + (const Complex& p);

};

Complex::Complex(int x = 0, int y = 0)
{
this->a = x;
this->b = y;
}

int Complex::getA()
{
return a;
}

int Complex::getB()
{
return b;
}

Complex Complex::operator + (const Complex& p) // 第二个参数由this传入
{
Complex ret;

ret.a = this->a + p.a;
ret.b = this->b + p.b;

return ret;

}

int main()
{
Complex c1(1, 2);// 调用构造函数初始化
Complex c2(3, 4);

Complex c3 = c1 + c2; 	// c1.operator + (c2)
cout << c3.getA() << "." << getB() << endl;

return 0;

}

21、重载 - 赋值操作符的重载
// 当类的成员指代了外部资源,就需要重载赋值操作符来完成深拷贝
#include
#include

using namespace std;

class Test
{
int* m_pointer;
public:
Test()
{
m_pointer = NULL;
}
Test(int i)
{
m_pointer = new int(i);
}
Test(const Test& obj)
{
m_pointer = new int(*obj.m_pointer);
}
Test& operator = (const Test& obj)
{
if( this != &obj )
{
delete m_pointer;
m_pointer = new int(*obj.m_pointer);
}

    return *this;
}
void print()
{
    cout << "m_pointer = " << hex << m_pointer << endl;
}
~Test()
{
    delete m_pointer;
}

};

int main()
{
Test t1 = 1;
Test t2;

t2 = t1;

t1.print();
t2.print();

return 0;

}

22、重载 - 数组操作符的重载
// 只能通过类的成员函数重载
// 重载函数能且仅能使用一个参数
// 可以定义不同参数的多个重载函数
#include
#include

using namespace std;

class Test
{
int a[5];
public:
int& operator [] (int i)
{
return a[i];
}

int& operator [] (const string& s)
{
    if( s == "1st" )
    {
        return a[0];
    }
    else if( s == "2nd" )
    {
        return a[1];
    }
    else if( s == "3rd" )
    {
        return a[2];
    }
    else if( s == "4th" )
    {
        return a[3];
    }
    else if( s == "5th" )
    {
        return a[4];
    }

    return a[0];
}

int length()
{
    return 5;
}

};

int main()
{
Test t;

for(int i=0; i<t.length(); i++)
{
    t[i] = i;
}

for(int i=0; i<t.length(); i++)
{
    cout << t[i] << endl;
}

cout << t["5th"] << endl;
cout << t["4th"] << endl;
cout << t["3rd"] << endl;
cout << t["2nd"] << endl;
cout << t["1st"] << endl;

return 0;

}

21、字符串类 - string
1、cin
2、cin.get()
3、cin.getline()
4、getline()
5、gets()
6、getchar()

1、cin>>
// >> 是会过滤掉不可见字符(如 空格 回车,TAB 等)
main ()
{
char a[20];
cin>>a>>b;
cout<<a+b<<endl;
}
输入:2[回车]3[回车]
输出:5
输入:jkljkl jkljkl //遇空格结束
输出:jkljkl
2、cin.get()
// 用来接收一行字符串,可以接收空格
main ()
{
char a[20];
cin.get(a,20);
cout << a << endl;
}
输入:jkl jkl jkl
输出:jkl jkl jkl
输入:abcdeabcdeabcdeabcdeabcde (输入25个字符)
输出:abcdeabcdeabcdeabcd (接收19个字符+1个’\0’)

3、cin.getline()
// 接受一个字符串,可以接收空格并输出
main ()
{
char m[20];
cin.getline(m,5);
cout<<m<<endl;
}
输入:jkljkljkl
输出:jklj

4、getline()
// 接受一个字符串,可以接收空格并输出,需包含“#include”
// cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数
main ()
{
string str;
getline(cin, str);
cout<<str<<endl;
}
输入:jkljkljkl
输出:jkljkljkl
输入:jkl jfksldfj jklsjfl
输出:jkl jfksldfj jklsjfl

// substr(size_type _Off = 0,size_type _Count = npos) const;
该系统函数返回被截后的子字符串,它接受2个必选参数,参数1为要截取的字符串,参数2为截取的开始位置,参数3可选,表示截取长度。
int main()
{
string s(“12345asdf”);
string a = s.substr(0,5); //获得字符串s中从第0位开始的长度为5的字符串

cout << a << endl; // 12345
}

#include
#include

using namespace std;

void string_sort(string* a, int len)
{
for(int i=0; i<len; i++)
{
for(int j=i; j<len; j++)
{
if( a[i] > a[j] )
{
swap(a[i], a[j]);
}
}
}
}

string string_add(string* a, int len)
{
string ret = “”;

for(int i=0; i<len; i++)
{
    ret += a[i] + "; ";
}

return ret;

}

int main()
{
string sa[7] =
{
“Hello World”,
“D.T.Software”,
“C#”,
“Java”,
“C++”,
“Python”,
“TypeScript”
};

string_sort(sa, 7);

for(int i=0; i<7; i++)
{
    cout << sa[i] << endl;
}
cout << endl;
cout << string_add(sa, 7) << endl;

return 0;

}

// 字符串和数字的转换
#include
#include
#include

using namespace std;

#define TO_NUMBER(s, n) (istringstream(s) >> n)
#define TO_STRING(n) (((ostringstream&)(ostringstream() << n)).str())

int main()
{
double n = 0;

if( TO_NUMBER("234.567", n) )
{
    cout << n << endl;
}

string s = TO_STRING(12345);
cout << s << endl;

return 0;

}

// 字符串右移
#include
#include

using namespace std;

string operator >> (const string& s, unsigned int n)
{
string ret = “”;
unsigned int pos = 0;

n = n % s.length();
pos = s.length() - n;
ret = s.substr(pos);
ret += s.substr(0, pos);

return ret;

}

int main()
{
string s = “abcdefg”;
string r = (s >> 3);

cout << r << endl;

return 0;

}

23、函数对象
// 函数对象的意义是取代函数指针
#include
#include

using namespace std;

int fib()
{
static int a0 = 0;
static int a1 = 1;

int ret = a1;

a1 = a0 + a1;
a0 = ret;

return ret;

}

int main()
{
for(int i=0; i<10; i++)
{
cout << fib() << endl;
}

cout << endl;

for(int i=0; i<5; i++)
{
    cout << fib() << endl;
}

return 0;

}

///////////////////////////////////////////
#include
#include

using namespace std;

class Fib
{
int a0;
int a1;
public:
Fib()
{
a0 = 0;
a1 = 1;
}

Fib(int n)
{
    a0 = 0;
    a1 = 1;

    for(int i=2; i<=n; i++)
    {
        int t = a1;

        a1 = a0 + a1;
        a0 = t;
    }
}

int operator () () //
{
    int ret = a1;

    a1 = a0 + a1;
    a0 = ret;

    return ret;
}

};

int main()
{
Fib fib;

for(int i=0; i<10; i++)
{
    cout << fib() << endl;
}

cout << endl;

for(int i=0; i<5; i++)
{
    cout << fib() << endl;
}

cout << endl;

Fib fib2(10);

for(int i=0; i<5; i++)
{
    cout << fib2() << endl;
}

return 0;

}

24、智能指针
// 重载->和* 解决内存泄漏
// 指针的生命周期结束时主动释放堆空间
// 一片堆空间只能由一个指针标识
// 杜绝指针比较和指针运算
#include
#include

using namespace std;

class Test
{
int i;
public:
Test(int i)
{
this->i = i;
}
int value()
{
return i;
}
~Test()
{
}
};

int main()
{
for(int i=0; i<5; i++)
{
Test* p = new Test(i);

    cout << p->value() << endl;
}

return 0;

}

#include
#include

using namespace std;

class Test
{
int i;
public:
Test(int i)
{
cout << “Test(int i)” << endl;
this->i = i;
}
int value()
{
return i;
}
~Test()
{
cout << “~Test()” << endl;
}
};

class Pointer
{
Test* mp;
public:
Pointer(Test* p = NULL)
{
mp = p;
}
Pointer(const Pointer& obj)
{
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}
Pointer& operator = (const Pointer& obj)
{
if( this != &obj )
{
delete mp;
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}

    return *this;
}
Test* operator -> ()
{
    return mp;
}
Test& operator * ()
{
    return *mp;
}
bool isNull()
{
    return (mp == NULL);
}
~Pointer()
{
    delete mp;
}

};

int main()
{
Pointer p1 = new Test(0);

cout << p1->value() << endl;

Pointer p2 = p1;

cout << p1.isNull() << endl;

cout << p2->value() << endl;

return 0;

}

25、类型转换
// explicit用于杜绝隐式转换
// 转换构造函数(有且仅有一个参数 参数是基本类型或者其他类型)
#include
#include

using namespace std;

class Test
{
int mValue;
public:
Test()
{
mValue = 0;
}

explicit Test(int i)
{
    mValue = i;
}

Test operator + (const Test& p)
{
    Test ret;
    ret = mValue + p.mValue;

    return ret;
}

int value()
{
    return mValue;
}

};

int main()
{
Test t;
Test r;

t = static_cast<Test>(5);   		// t = Test(5);
r = t + static_cast<Test>(10); 	// r = t + Test(10);

cout << r.value() << endl;

return 0;

}

// 类型转换函数

26、继承 – 概念
// 继承父类的成员函数中,调用的变量也来自父类,隐藏但不会覆盖,他们同时存在
class Parent
{
public:
string mv;

Parent():mv("Parent")
{
    cout << "Parent()" << endl;

}

void method()
{
    cout << "mv = " << mv << endl;
}

};

class Child : public Parent
{
public:
string mv;

void hello()
{
    cout << "I'm Child class!" << endl;
}

};

int main()
{
Child c;

c.hello();
c.method();		// 成员函数继承自父类 成员函数的变量也是父类的(虽然被隐藏)

return 0;

}
27、继承 – protected
// protected是为了对外界隐藏敏感信息,不能被外界直接访问,可以被子类直接访问
class Parent
{
protected:
int mv;

public:
Parent()
{
mv = 100;
}

int value()
{
    return mv;

}

};

class Child : public Parent
{
public:
int addValue(int v)// 子类可以在直接访问protected变量
{
mv = mv + v;
}
};

int main()
{
Parent p;
cout << "p.mv = " << p.value() << endl;// 100

// p.mv = 1000;    // error 外界不能访问

Child c;
cout << "c.mv = " << c.value() << endl;	// 100

c.addValue(50);
cout << "c.mv = " << c.value() << endl;	// 150

// c.mv = 10000;  // error	main属于类的外部

return 0;

}

27、继承 – 构造和析构
// 析构函数应定义为虚函数
// 如果父类析构函数没有定义成虚函数,则编译器实现静态绑定,删除父类对象只调用父类的析构函数,二不析构子类对象,造成内存泄露。
class Base
{
public:
Base()
{
cout << “Base()” << endl;
}
virtual ~Base()
{
cout << “~Base()” << endl;
}

};
class Expend :public Base
{
public:
Expend()
{
cout << “Expend()” << endl;
}
~Expend()
{
cout << “~Expend()” << endl;
}

};
int main()
{

Base *pd = new Expend; // 	Base()
					   	Expend()

delete pd; // ~Expend() 父类析构函数不加virtual不会执行这一行
~Base()
}

// 先调用父类构造函数
// 再调用成员变量的构造函数
// 最后调用自身的构造函数
class Object
{
private:
string ms;

public:
Object(string s)
{
cout << "Object(string s) : " << s << endl;
ms = s;
}
virtual ~Object()
{
cout << "~Object() : " << ms << endl;
}
};

class Parent : public Object
{
private:
string ms;

public:
Parent() : Object(“Default”)
{
cout << “Parent()” << endl;
ms = “Default”;
}
Parent(string s) : Object(s)
{
cout << "Parent(string s) : " << s << endl;
ms = s;
}
~Parent()
{
cout << "~Parent() : " << ms << endl;
}
};

class Child : public Parent
{
private:
Object mO1;
Object mO2;
string ms;

public:
Child() : mO1(“Default 1”), mO2(“Default 2”)
{
cout << “Child()” << endl;
ms = “Default”;
}
Child(string s) : Parent(s), mO1(s + " 1"), mO2(s + " 2")
{
cout << "Child(string s) : " << s << endl;
ms = s;
}
~Child()
{
cout << "~Child() " << ms << endl;
}
};

int main()
{
Child cc(“cc”); // Object(string s) : cc \ 先父母
Parent(string s) : cc
Object(string s) : cc + 2 \ 后客人
Object(string s) : cc + 1 \ 再自己
Child(string s) : cc ;
cout << endl;
// ~Child() cc
~Object() : cc 1
~Object() : cc 2
~Parent() : cc
~Object() : cc

return 0;

}
28、继承 – 重定义(隐藏)

// 指在不同的作用域中,函数名相同,不能构成重写的都是重定义
// 子类的成员变量将隐藏父类中的同名成员变量
// 默认访问的是子类的成员,继承了但是不能直接访问,想访问父类用 ::分辨
class Parent
{
public:
int mi;

Parent()
{
    cout << "Parent() : " << "&mi = " << &mi << endl;
}

};

class Child : public Parent
{
public:
int mi;

Child()
{
    cout << "Child() : " << "&mi = " << &mi << endl;
}

};

int main()
{
Child c;

c.mi = 100;    		// 访问子类的变量

c.Parent::mi = 1000;// 访问父类的变量

cout << "&c.mi = " << &c.mi << endl;				// 0xbfb04e28
cout << "c.mi = " << c.mi << endl;					// 100

cout << "&c.Parent::mi = " << &c.Parent::mi << endl;	// 0xbfb04e24
cout << "c.Parent::mi = " << c.Parent::mi << endl;		// 1000

return 0;

}

// 子类的函数将隐藏父类的同名函数
// 由于再不同的作用域,子类不能重载父类的同名函数,用作用域分辨符::区分
class Parent
{
public:
int mi;

void add(int v)
{
    mi += v;

cout << “Child::add(int)” << endl; }

void add(int a, int b)
{
    mi += (a + b);

cout << "Parent::add(int, int) " << endl;
}
};

class Child : public Parent
{
public:
int mi;

void add(int x, int y, int z)
{
    mi += (x + y + z);
}

};

int main()
{
Child c;

c.Parent::mi = 1000;

c.mi = 100;

c.add(1);						// 编译不通过 子类同名函数隐藏父类,不存在重载
c. Parent::add(2, 3);			// Parent::add(int, int)
c.add(4, 5, 6);					// Child::add(int, int, int)

cout << "c.Parent::mi = " << c.Parent::mi << endl;// 1005
cout << "c.mi = " << c.mi << endl;// 116

return 0;

}

29、继承 – 赋值兼容
// 面向对象赋值兼容规则
1.子类对象可以赋值给父类对象
2.子类对象可以初始化父类对象
3.父类指针可以指向子类对象
4.父类引用可以引用子类对象
// 当父类指针(引用)指向子类对象时,子类对象退化成父类对象,只能访问父类中定义的成员
class Parent
{
public:
int mi;

void add(int i)
{
    mi += i;
}

void add(int a, int b)
{
    mi += (a + b);
}

};

class Child : public Parent
{
public:
int mv;

void add(int x, int y, int z)
{
    mv += (x + y + z);
}

};

int main()
{
Parent p;
Child c;

p = c;			// 1.子类对象可以赋值给父类对象

Parent p1(c);		// 2.子类对象可以初始化父类对象


Parent& rp = c;	// 3.父类引用可以引用子类对象
Parent* pp = &c;	// 4.父类指针可以指向子类对象

rp.mi = 100;
rp.add(5);      	// 子类对象c已经退化成父类对象
rp.add(10, 10);

/* 为什么编译不过? */
// pp->mv = 1000;
// pp->add(1, 10, 100);

return 0;

}

// 重写父类函数,不加virtual的话编译器默认指向父类
class Parent
{
public:
void print()
{
cout << “I’m Parent.” << endl;
}
};

class Child : public Parent
{
public:
void print()
{
cout << “I’m Child.” << endl;
}
};

int main()
{
Child c;
Parent *p;

p = &c;

p->print();// I’m Parent. 默认指向父类函数

return 0;

}
30、继承 – 重写(覆盖 多态)
// 当在子类中定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写了父类这个虚函数。
// 根据实际指针指向的对象判断调用函数
// 子类重写父类函数,必须用virtual修饰,不然没有意义。因为默认调用父类函数
// 静态联编:在程序的编译期就能确定函数的具体调用 重载
// 动态联编:在程序的执行期才能确定函数的具体调用 重写
class Parent
{
public:
virtual void print()
{
cout << “I’m Parent.” << endl;
}
};

class Child : public Parent
{
public:
void print()
{
cout << “I’m Child.” << endl;
}
};

void how_to_print(Parent* p)
{
p->print(); // 多态性 根据p指向的对象不同,有不同的输出结果
}

int main()
{
Parent p;
Child c;

p.print();				//  I'm Parent. 	静态联编

c.print();// I’m Child.静态联编
cout<<endl;

how_to_print(&p);  	//  I'm Parent. 	动态联编
how_to_print(&c);   	//  I'm Child.		动态联编

return 0;

}

2、泛型编程 – 单例类模板
//

2、泛型编程 – 函数模板
// template
// 函数模板是一种特殊的函数,可用不同类型进行调用, 类型可被参数化
#include
#include

using namespace std;

template < typename T >
void Swap(T& a, T& b)
{
T c = a;
a = b;
b = c;
}

int main()
{
int a = 0;
int b = 1;

Swap(a, b);

cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << endl;


double x = 1.234;
double y = 4.321;

Swap(x, y);		// 隐式调用

cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << endl;

string m = "Dazhang";
string n = "yu";

Swap<string>(m, n); // 显式调用

cout << "m = " << m << endl;
cout << "n = " << n << endl;
cout << endl;

return 0;

}

// template <typename T1, typename T2, typename T3>
// 多参数函数模板无法自动推导返回值类型,第一个参数为返回值类型,且必须
#include
#include

using namespace std;

template < typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
return static_cast(a + b);
}

int main()
{
// T1 = int, T2 = double, T3 = double
int r1 = Add(0.5, 0.8);

// T1 = double, T2 = float, T3 = double
double r2 = Add<double, float>(0.5, 0.8);

// T1 = float, T2 = float, T3 = float
float r3 = Add<float, float, float>(0.5, 0.8);

cout << "r1 = " << r1 << endl;     // r1 = 1
cout << "r2 = " << r2 << endl;     // r2 = 1.3
cout << "r3 = " << r3 << endl;     // r3 = 1.3

return 0;

}

// 编译器优先选用普通函数
// 可通过空模板实参列表限定值匹配模板
#include
#include

using namespace std;

template < typename T >
T Max(T a, T b)
{
cout << “T Max(T a, T b)” << endl;

return a > b ? a : b;

}

int Max(int a, int b)
{
cout << “int Max(int a, int b)” << endl;

10-07 15:32