几个术语翻译
explicit:明确的
implicit:隐含的
trivial:没有意义的
non-trivial:有意义的
1.构造函数
构造函数中应该执行一些打酱油的工作,具体工作应该由
Init函数中处理,但是问题是
当外部NEW出对象来之后,不调用Init直接使用,该对象
需要如何回应,需要负责到哪个地步?
如果要负全部责任的话,
看起来对于不确定状态这种情况,需要使用成员标记指示,
至少可以明确答复失败,不至于出现崩溃等异常情况。
下面就一个例子分析一下
1.h
typedef struct
{
char test[20];
int m;
}TEST_S;
class test
{
public:
test();
~test();
int init();
void printMsg();
private:
TEST_S* test1;
};
1.cpp
#include "1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
test::test():test1(NULL)
{
}
test::~test()
{
if(NULL != test1)
{
free(test1);
test1 = NULL;
}
}
int test::init()
{
test1 = (TEST_S*)malloc(sizeof(TEST_S));
if(NULL == test1)
{
printf("Malloc failed\n");
return -1;
}
strcpy(test1->test,"ABC");
test1->m = 2;
return 0;
}
void test::printMsg()
{
printf("Msg:[%s]\n",test1->test);
printf("Msg:[%d]\n",test1->m);
return;
}
test.cpp
#include "1.h"
int main()
{
test testm;
testm.init();//INIT不调用直接调用函数会有CRASH等异常问题
testm.printMsg();
}
这个例子中 类test提供了init函数给外部,也就是说规定外部必须调用Init,不然的话
接下来的函数调用就不成功,道理是这样,但问题是,不成功的形式,
从上面这个例子看来,不成功就哦了,面子上太过不去了。
如果要完善的话,就需要test内部增加一个运行标记,检查到init没调用就调其他函数
一律回绝,双管齐下的话看起来是一个可以运行的方案。
考虑string类
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
string a("5");
printf("%s\n",a.c_str());
return 1;
}
看起来STL和GOOGLE C++是要对着干的态度,还是string类的内部结构隐藏一个惊天秘密?
2.默认构造函数
没有什么可说的,总之要自己定义,不能自动生成
3.明确的构造函数
防止单参数构造函数隐式转换
test.cpp
#include <stdio.h>
#include <string>
using namespace std;
class MyClass
{
public:
explicit MyClass(string name);
~MyClass();
private:
};
MyClass::MyClass(string name)
{
printf("con [%s]\n",name.c_str());
}
MyClass::~MyClass()
{
}
int main()
{
//MyClass A = "ABC";//不加explicit可以编译通过。
MyClass A("ABC");
}
4.拷贝构造函数与赋值函数
一般来说就是直接关小黑屋(private),可能用的较多的就是STL了。
就用这个DISALLOW_COPY_AND_ASSIGN
5.结构体和类
总体来说结构体还是C一样的使用风格,包括内存申请方式也是用malloc为好。(形式上)
如果用new,又想用memset初始化的话,可能会导致非法初始化非POD的严重问题。
扩展阅读。
A plain old data structure (POD) is a data structure that is represented only as passive collections of field values, without using encapsulation or other object-oriented features.
http://zh.wikipedia.org/wiki/POD_(%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)
6.继承
文档强调组合大于继承,只有在子类是基类的基础上才进行继承,例如,飞机是交通工具。
如果有一个类实现了飞行的功能,那么这个类更适合组合(拥有)
在含有虚函数的父类中,定义析构虚函数是必要的(一般来说都是必要的)
子类的虚函数明确标出VIRTURE,没有实际意义,就是要标一下
7.多重继承
一般估计用不到
8.接口
也不常用
9.操作符重载
一般不用,本着科学发展关写个例子意思一下
#include <iostream>
using namespace std;
class test{
public:
test::test():x(0)
{
};
test::~test()
{
};
int x;
};
test operator+(const test &test1, const test &test2){
test testm;
testm.x = test1.x + test2.x;
return testm;
}
int main()
{
test testn;
testn.x = 2;
test testn1;
testn1.x = 3;
test testn2 = testn + testn1;
cout << testn2.x << endl;
return 1;
}
10.声明次序
在类中使用特定的声明次序:public:在private:之前,成员函数在数据成员(变量)前。
定义次序如下:public:、protected:、private:,如果那一块没有,直接忽略即可。
每一块中,声明次序一般如下:
1) typedefs和enums;
2) 常量;
3) 构造函数;
4) 析构函数;
5) 成员函数,含静态成员函数;
6) 数据成员,含静态数据成员。
宏DISALLOW_COPY_AND_ASSIGN置于private:块之后,作为类的最后部分。参考拷贝构造函数。
.cc文件中函数的定义应尽可能和声明次序一致。
人民群众喜闻乐见的八股文啊