【cpp基础篇-01】面向对象
一、头文件与命名空间
1. 头文件是什么
例:A.cpp, A.h, B.cpp
A.h 头文件 中写入类声明、函数原型、#define;
A.cpp实现文件 写入类函数的定义实现;
B.cpp调用文件 通过一个宏命令 "#include" 调用A.h中的类和函数等
[注1] 头文件无需编译,只需在源文件预处理时被合并
[注2]#include功能仅是简单的文本替换
[注3]系统头文件用< >, 自定义头文件用" "
//头文件的防御式编程
#ifndef A_H
#define A_H
//...
#endif
2.几个特殊情况
(1)static修饰变量、函数可以写在.h文件中
(2)inline内联函数定义可以写在.h文件中
(3)模板类型可以写在.h中,模板在调用时才编译
3.命名空间
区分不同库中相同名称的函数、类、变量
- 定义
namespace namespace_name {
// 代码声明
}
- 调用
name::code; // code 可以是变量或函数
//后续的代码将使用指定的命名空间中的名称。
using namespace namespace_name;
//指定命名空间中的特定项目
using std::cout;
二、面向对象编程
1.语法点
1.1 private、public、protected
(1)数据防止泄露,通常为private。
(2)protected可由派生类访问。
(3)同一类的不同对象可以相互访问private变量、函数。
1.2 inline
(1)内联函数的两种写法:
- 定义写在类内
- 定义写在类外,加上inline前缀
(2)内联函数只是一种建议,具体实现由编译器决定
(3)内联函数减少了运行栈保存变量的开销
1.3 const
(1)const成员变量:不应被改变
(2)const成员函数:不应改变成员变量的值
(3)const对象:只能访问被 const 修饰的成员函数、变量
(4)const int* p与int* const p
1.4 static
static类型属于类,对象间共享内存
(1)static成员变量
(2)stattic成员函数
- 只能访问静态成员变量
- 声明时加static,定义时不加static
1.5 friend
【友元函数】
(1)友元函数不是类的成员函数,在类中声明,类外定义
(2)友元函数有权访问类的private、protected、public函数和变量。
(3)友元函数必须通过参数传递对象才能访问类的成员
【友元类】
(1)友元类中的所有成员函数都是另外一个类的友元函数。
2.面向对象的难点问题
2.1 构造函数
- 初始化问题
complex(double r, double i):re(r),im(i) {}
提前初始化,而不是用assign赋值有利于提高性能。 - 构造函数可以重载
- private中的构造函数:单例模式
2.2 操作符重载问题
- 操作符重载的两种方法
成员函数方法:a.op(b),含有返回值满足连续op的情况;
全局函数+友元函数方法:op(a,b); - 不能重载的操作符
.
?:
::
sizeof
- 运算符重载不改变优先级
2.3 copy问题
- 深拷贝 和 浅拷贝
浅拷贝:类内变量创建副本,类内指针共享内存
深拷贝:需要自定义重载 - 默认拷贝为浅拷贝,含指针的类可能出现内存泄露
- 拷贝构造copy ctor 和 拷贝赋值copy op=
copy op= 等价于 自我赋值检测 + delete_self + copy ctor
2.4 析构函数问题
- 类内存在动态分配内存的情况时(往往表现为含指针),需要添加析构函数
- 普通对象:消亡时自动调用析构函数
- 指针对象:注意new与delete的匹配问题
2.5 值、指针、引用
2.5.1 value 与 reference
- value:默认为浅拷贝,内存开销大
- reference:变量别名,共享内存
- 返回局部变量时,不能声明为reference,因为局部变量在函数结束时销毁
2.5.2 reference 与 pointer
- pointer可能为null,reference必须被初始化
- pointer可以改变,reference不能更改
二、示例
1.类不含指针(Complex)
代码如下(示例):
#include<iostream>
using namespace std;
class Complex{
private:
double real, imag;
public:
//默认构造函数
Complex(){ }
//重载构造函数 + 初始化列表
Complex(double r, double i): real(r), imag(i){ }
//成员函数 的 操作符重载 + 临时对象
Complex operator+(const Complex& c) const{
//返回local变量不能使用reference
return Complex(real + c.real, imag + c.imag);
}
//全局函数 的 操作符重载 + 友元函数
friend ostream& operator<<(ostream& os, Complex& c);
friend Complex& operator+=(Complex& c1, const Complex& c2);
/*
Complex& operator+=(const Complex& c2)
{
this->real += c2.real;
this->imag += c2.imag;
}
*/
};
Complex& operator+=(Complex& c1, const Complex& c2){
c1.real += c2.real;
c1.imag += c2.imag;
return c1;
}
ostream& operator<<(ostream& os, Complex& c){
os << "(" << c.real << "," << c.imag << ")";
return os;
}
int main()
{
Complex c1;
Complex c2(5,5);
const Complex c3(5,5);
c2 += c3;
c1 = c2 + c3;
cout<<c1<<endl;
}
2.类含指针(String)
代码如下(示例):
#include<iostream>
#include<cstring>
/*
注:
cstring:c++版的string.h
string: stl范畴
string.h: c语言库,c++兼容
*/
using namespace std;
class String{
private:
char* m_data;
public:
String(const char* cstr = 0);
//copy ctor
String(const String& s);
//copy op=
String& operator=(const String& s);
//析构函数
~String();
char* get_str() const{
return m_data;
}
friend ostream& operator<<(ostream& os, const String& s);
};
//注:不能同时在 声明 和 定义 中写默认参数
inline
String::String(const char* cstr){
if(cstr){
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else{
m_data = new char[1];
*m_data = '\0';
}
}
inline
String::~String(){
delete[] m_data;
}
inline
String::String(const String& s){
//深拷贝
m_data = new char[ strlen(s.m_data) + 1 ];
strcpy(m_data, s.m_data);
}
inline
String& String::operator=(const String& s){
//step1:检查自我赋值
//注意指针细节:&s,this:地址;s,*this:string内容
if(&s == this){
return *this;
}
//step2:删除空间
delete[] m_data;
//step3:copy ctor
m_data = new char[ strlen(s.m_data) + 1 ];
strcpy(m_data, s.m_data);
return *this;
}
ostream& operator<<(ostream& os, const String& s)
{
os<<s.get_str();
return os;
}
int main()
{
const String s2("duan");
const String s3("shuai");
String s1(s2);
cout<<s1<<endl;
s1 = s3;
cout<<s1<<endl;
}