一.面向对象的优点:
(1)良好的可复用性
(2)易维护
(3)良好的可扩充性
二.面向对象的基本概念
对象,类和继承
三.注意初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的
重点:初始化列表的初始化顺序,如果你直接用等于那就不一样了
四.常量必须在构造函数的初始化列表里面初始化或者将其设置成static
五.为什么说虚拟的析构函数是必要的?
这是为了对抗多态,比如说
B类继承A类
此时有A类指针指向B类则在析构的时候由于是静态联编,所以调用的是A类的析构函数,这就有可能造成内存泄漏
相反的,将A类的析构函数设为virtual型,则所以体验CObject类的派生类的析构函数都将自动变为virtual型
保证了任何情况下,不会出现由于析构函数未被调用而导致的内存泄漏。
六.析构函数可以为virtual型,构造函数则不能,那么为什么构造函数不能为虚?
虚函数采用一种虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数,但是如果要创建一个对象,你势必要知道对象的准确类型,因此构造函数不能为虚。
七.虚函数如此有效我们是否可以把每个函数都声明为虚函数?
不行,这是因为虚函数是有代价的,由于每个虚函数的对象都必须维护一个v表,因此在使用虚函数的时候都会产生一个系统开销,如果仅是一个很小的类,且不想派生其他类,那么根本没必要使用虚函数。
八.String的赋值函数注意检查自赋值
class String
{
public:
//普通构造函数
String(const char* str = NULL);
//拷贝构造函数
String(const String &other);
//析构函数
~String(void);
//赋值函数
String &operator =(const String &other);
private:
//用于保存字符串
char* m_data;
};
String::~String(void)
{
delete[] m_data;
}
String::String(const char* str)
{
if (str == NULL)
{
m_data = new char[1];
*m_data = '\0';
}
else
{
int length = strlen(str);
m_data = new char[length + 1];
strcpy(m_data, str);
}
}
String::String(const String& other)
{
if (other.m_data == NULL)
{
m_data = NULL;
}
else
{
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
}
}
String &String::operator = (const String& other)
{
//const的作用
//保证可以赋值常量
//还有保证s9=s7+s8;s9等都是String对象
//检查自赋值
if (this == &other)
{
return *this;
}
delete[] m_data;
//分配新的内存资源并复制内容
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
//返回本对象的引用
return *this;
}
九.
重载和多态的区别
重载:参数列表不同
多态:参数列表相同,一个接口,多种方法,接口重用
十.友元函数
例子
class Point
{
private:
float x;
float y;
public:
Point(float a = 0.0f, float b = 0.0f) :x(a),y(b) {};
friend float distance(Point& left, Point& right);
};
float distance(Point& left, Point& right)
{
return sqrt(((left.x - right.x) *(left.x - right.x) + (left.y - right.y) *(left.y - right.y))) ;
}