c++编程
c++
c++是c的超集,因此这里你将会学到更多的技术。和Objective-C相比,c++有不少不一样的概念和语法,尽管他们都是面向对象的编程语言。他们有不少重要的不一样之处:类,指针,多重继承,内存管理,和模板。sql
class类数据库
这点和Objective-C相似,一个类有两个文件:一个是头文件,另外一个是实现文件。你一样能够指定private和public的成员或方法。下面是声明一个类的头文件的标准方式:编程
class Cat { 编程语言
public:
ide
// public accessors
unsigned int GetAge();
void SetAge(unsigned int Age);函数
Cat ();
Cat (int initialAge);~Cat();性能
// public member functions学习
void Meow();ui
// private member data
private:
unsigned int itsAge;
};
// GetAge, Public accessor function
// returns value of itsAge member
unsigned int Cat::GetAge() {
return itsAge;
}
// returns sets itsAge member
void Cat::SetAge(unsigned int age) {
// set member variable its age to
// value passed in by parameter age
itsAge = age;
}
// action: Prints "meow" to screen
void Cat::Meow() {
cout << "Meow.\n";
}
int main() {
Cat cat;
cat.Meow();
}
你能够看到,public和private声明能够分开放在不一样地方,就像Objective-C中定义头文件时使用的修饰符@private和@public。对于类的实现,你须要在方法的前面加上类的名称,来代表方法是属于这个类的。
对于访问和设置方法,你须要显示的声明他们:
unsigned int GetAge();
void SetAge(unsigned int Age);
为了建立一个Cat对象,你只须要声明Cat cat;而后调用方法cat.Meow();可是对象只存在函数的局部范围内部。
对于内存管理,你须要同时声明构造函数和析构函数。若是没有声明你本身的构造函数,编译器会使用一个没有参数的默认构造函数。
注意:若是声明了本身的构造函数,请记住也要声明析构函数,即便它没有作什么事情。遵照这个预约是很是好的。若是使用Cat cat建立Cat的一个新对象,你须要一个默认构造函数。 |
指针和内存管理
若是你想要在程序其余地方使用你新建立的对象,在c++中,你须要在自由存储区中申请分配内存。这个对象会一直存在,直到你显示的在内存中把它删除,就像c语言同样。为了声明指向一个包含整型值的内存地址指针,你能够像这样:
int *pInt;
pInt = new int;
*pInt = 72;
分配和释放一个对象,你可使用new和delete关键字。
Cat *pCat = new Cat;
pCat->SetAge(5);
delete pCat;
pCat = 0;
注意:若是你delete同一个指针两次,你的应用会崩溃。若是你在从新分配以前没有delete它,会有内存泄露。 |
继承
相比于Objective-C,c++继承的概念更加复杂。你能够像正常同样使用继承,复写,多态。惟一不一样的是virtual和pure virtual方法。
class Dog : Mammal {
}
Dog类继承了Mammal类的全部属性和方法,同时它可以有本身的属性和方法。当Dog对象被建立的时候,Mammal的构造函数先调用,而后在调用Dog的构造函数。
c++继承中有一个很是重要的概念:你只可以复写virtual方法。对于其余方法,你只能继承而不能复写。在父类和子类中能够有两个同名的方法,可是不存在复写和多态。对于virtual方法,建议在必要的时候在子类中进行复写。c++中方法默认的修饰符是非virtual的。有两种类型的虚函数:虚函数和纯虚函数。
#include "stdafx.h"
#include "stdio.h"
using namespace System;
class Animal {
public:
virtual void Speak() = 0;
virtual void Eat();
void Run();
};
void Animal::Eat(){
printf("Animal eats\n");
}
void Animal::Run(){
printf("Animal runs\n");
}
class Dog : Animal{
public:
void Eat();
void Speak();
void Run();
};
void Dog::Eat(){
printf("Dog eats\n");
}
void Dog::Run(){
printf("Dog runs\n");
}
void Dog::Speak(){
printf("Dog speaks\n");
}
int main(){
Animal *dog1 = (Animal *) new Dog;
dog1->Run();
dog1->Speak();
dog1->Eat();
getchar();
}
对于虚函数,在父类中你能够有它的实现;可是对于纯虚函数,你只能声明。Eat方法是虚函数,而Speak是纯虚函数。在子类中,这两个方法都须要复写。
由于Run不是虚函数,子类不须要复写。所以main函数的输出将是
Animal Runs
Dog Speaks
Dog Eats
多重继承
在c++中,你的类能够继承不少父类,所以你可以重用更多的属性和方法。例如,Teacher类同时继承Employee和Person类,如如9-4。
你能够经过下面这样进行多重继承
class Teacher : public Person, public Employee {
}
多重继承存在一个广泛的问题:当两个父类有相同的方法时。例如,Pesron和Employee两个类都声明了GetIncome方法。所以,当你在Teacher对象中调用此方法时,你必须显示的指定是调用哪一个父类的方法。
若是你只是这样写
int currentIncome = pTeacherGetIncome();
你会获得一个编译错误
Member is ambiguous: ‘Person::GetIncome’ and ‘Employee::GetIncome’
你须要显示的指明调用哪一个父类的函数来消除这个二义性。
int currentIncome = pTeacherEmployee::GetIncome();
模板
在c++中,你能够定义类或方法只接收某种指定的类型。例如,你能够定义一个方法,只接收两个同类型的参数进行比较而后返回结果。
template <class T>
T GetMax (T a, T b) {
return (a>b)? a : b;
}
int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax<int>(i,j);
n=GetMax<long>(l,m);
return 0;
}
经过定义一个模板方法,你能够确保a和b是一样的数据类型,这样他们就能够进行比较。你能够在类中也进行一样的操做。
template <class T>
class mypair {
T a, b;
public:
mypair (T first, T second){
a=first;
b=second;
}
T getmax () {
return a>b? a : b;
}
};
int main () {
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
一个实际例子
我将经过一个实际的例子来引导你如何将c/c++库集成到Objective-C代码中。一个例子是集成SQLite库,另外一个例子是讲c++和Objective-C代码进行混编。
SQLite
SQLite是CoreData的底层实现。SQLite性能仍是不错的,由于比较轻量级和更加直接。可是,CoreData在这些方法提供了更好的支持:模型对象匹配,undo和redo功能,批量操做,线程。
使用SQLite的最大好处是:若是你的团队已经很熟悉相关的数据库和SQL,学习的曲线也是很是轻量级的。SQLite一样很容易移植到Android中,这样比就能够在iPhone和Android应用共享相同的数据了。
你能够阅读SQLiteSample工程的源代码。这里我只给你一些重要的提示。
你须要打开命令行,而后书输入sqlite3 students.sql 来建立数据库。这会建立一个新的数据库,而后就能够在这个数据库中建立表,插入和查询数据。你可使用SQL语句建立表和插入数据。
sqlite> CREATE TABLE students (pk INTEGER PRIMARY KEY, name VARCHAR(25));
sqlite> INSERT INTO students (name) VALUES ('khang');
sqlite> INSERT INTO students (name) VALUES ('vo');
sqlite> INSERT INTO students (name) VALUES ('duy');
sqlite> .quit
图9-5更加清楚的展现了在命令行中发生的事情。
你能够在Home文件夹(这个是默认的文件夹,若是你在终端操做时没有修改的话)下找到students.sql文件。你须要把这个文件添加到Xcode中,而后要添加libsqlite3.0.dylib这个库。
- (void)viewDidAppear:(BOOL)animated {
NSString *path = [[NSBundle mainBundle] pathForResource:@"students" ofType:@"sql"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
// Get the primary key for all books.
const char *sql = "SELECT pk, name FROM students";
sqlite3_stmt *statement;
// Preparing a statement compiles the SQL query into a byte-code program in theSQLite library.
// The third parameter is either the length of the SQL string or -1 to read up tothe first null terminator.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
// We "step" through the results - once for each row.
while (sqlite3_step(statement) == SQLITE_ROW) {
const unsigned char *name = sqlite3_column_text(statement, 1);
NSString *nameString = [NSString stringWithCString:(char *)nameencoding:NSASCIIStringEncoding];
}
}
// "Finalize" the statement - releases the resources associated with thestatement.
sqlite3_finalize(statement);
} else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSAssert1(0, @"Failed to open database with message '%s'.",
sqlite3_errmsg(database));
}
[self.tableView reloadData];
}
这里有一些方法你须要记住:
sqlite3_open([path UTF8String], &database) == SQLITE_OK 初始化和将新的数据库对象赋值给你的指针。
sqlite3_prepare_v2(database, sql, -1, &statement, NULL) ==SQLITE_OK 执行sql命令和把结果放入statement中。
while (sqlite3_step(statement) == SQLITE_ROW): 从执行的statement中遍历结果。
在你的应用中集成c++
你能够绝不费力的将c集成到你的应用中,由于Objective-C是c的超集。可是,当你在应用中集成c++的时候,你须要注意一些细节。
首先,你须要像正常同样的建立c++类的头文件和实现文件(.h和.cpp文件)。而后,你须要把包裹c++文件的Objective-C文件的后缀改成.mm(在iOS环境中这些是Objective-C++文件)。任何想要使用.mm文件的文件也必须像a.mm这样。
你能够查看一下TestC_CPlus这个示例工程。首先,你会看到两个文件,Foo_Cpp.h 和Foo_Cpp.cpp,他们声明了Foo_Cpp这个c++类。而后,经过MyObject.h和MyObject.m这两个Objective-c++文件进行包裹。
最后一步,把这些逻辑集成到你的view controller中。你能够在工程中像正常同样调用MyObject对象。你只须要将把调用的文件后缀改成.mm。
总结
在编程领域中,已经有不少高性能的和由特殊任务的c/c++库。你永远不须要重复发明轮子,或努力的将c/c++代码转换成Objective-c代码。理解c/c++可以帮助你更好的理解库的使用,这样你就可以把他们集成到你的应用中。
Objective-C是c的超集,因此不少c的特性你都已经知道了。我讨论了c编程的一些主要的点,包括指针的概念。你也学到了函数指针,位操做,这些都是c的特性,可以很好的提高性能。
若是你没有编程经验的话,c++比较难以学习和理解。我仅仅讨论了c++一些主要的知识点,c++和Objective-C的主要不一样之处。对于编写一个高要求的c++程序可能信息还不够,可是对于如何将一个已经存在的c++库集成到iPhone应用中已经足够了。
在最后一部分,我使用了一个SQLite的真实的例子展现了如何在Objective-C中使用C。这个并不难,除了一些语法和内存管理上的不一样。对于c++库我并无深刻讨论;我只是展现了如何将c++代码集成到你的iPhone应用中。