国外最新创意产品网站有哪些方面,网络营销方式有哪些各方式的优缺点有哪些,微信开发小程序工具,wordpress 新安装 慢类是 C中一个非常重要的元素#xff0c;可以说是 C的灵魂所在了#xff0c;我们都知道 C说一种面向对象的编程语言#xff0c;那么面向对象是一种什么概念呢#xff1f;在 C程序设计中#xff0c;所有一切东西都可以称之为对象#xff0c;任何对象都应该具有属性和行为。… 类是 C中一个非常重要的元素可以说是 C的灵魂所在了我们都知道 C说一种面向对象的编程语言那么面向对象是一种什么概念呢在 C程序设计中所有一切东西都可以称之为对象任何对象都应该具有属性和行为。例如一台电脑属性有电脑的相关配置功能是可以玩游戏可以打字等等。而类就是描述一个对象的一种概念例如我们创建一个人类那么人这个类其实就是一种概念并不是实际的某个人而是人的一些特征集合具体到某个人例如张三那么张三就是一个对象他有名字有身高体重行为可以跑步可以吃饭等等。所以我们一定要理解类其实就是保存一类对象的特征的集合。 在 c 语言中我们来表示一个东西的特征的时候我们使用的是结构体来表示例如表示一个人 struct person
{char name[16]; //名字float height; //身高float height; //体重char cell[32]; //手机号
}; 定义号一个人的属性之后如果想对这个人有所操作的话就要去定义函数然后去在主函数中去实现一些函数的过程逻辑所以说 c 语言是一种面对过程编程的语言而在 C中对结 构体进行了一个升级可以在里面去定义函数来表示这类对象的一些行为同时可在里面设置一些权限实现封装使其内部元素对外隐藏只提供一些对外接口和外部对接这就是 C的一个封装性。 class person
{private:char name[16]; //名字float height; //身高float weight; //体重char cell[32]; //手机号public:int running(char *WayName,int time); //跑步行为int eat(char *ObjectName,int l); //存放行为
}; class 和 struct 在 C中的区别 在 C中同样也是可以使用 struct 来表示类的它们所具有的功能完全一致只有以下几点不同 1.默认继承权限 使用 struct 默认继承权限是公有的(public),而 class 默认继承权限是私有的(private) 2.默认访问权限 struct 的默认访问权限是公有的而 class 的默认访问权限是私有的。 类的访问修饰符 访问修饰符描述了类中成员的访问权限(哪些成员是可以直接访问的哪些不能访问) [public]: public 修饰的成员称为公有成员在任何地方都可以直接访问 [private]: private 修饰的成员称为私有成员只有本类的成员函数和友元函数才可以访问 [protected]: protected 修饰的成员称为受保护的成员只有本类的成员函数和友元函数和它的派生类才可以访问 一般来说我们一般将类的属性信息设置为私有的外界不可访问这样就保护了我们的对象不被轻易改变而把一些行为接口设置为公有的供外部去对我们的这个对象进行操作。 构造函数和析构函数 在类中默认会有一个构造函数和一个析构函数在定义对象的时候程序会自动去执行构造函数对对象进行初始化释放对象时会自动调用析构函数去对对象进行释放构造函数的名字和类名一样没有返回值析构函数名字则是在类名的前面加上~号无参数也没有返回值程序员也可以重写构造函数和析构函数为对象中的属性值进行初始化和释放例如 #include iostream
#includestring.h
using namespace std;
class person
{private:char name[16]; //名字float height; //身高float weight; //体重char cell[32]; //手机号public:person();person(const char *ne,float h,float w,const char *ce);~person(){cout name :执行了析构 endl;}void run(){cout 名字 name endl;cout 身高 height endl;cout 体重 weight endl;cout 手机号 cell endl;}int running(char *WayName,int time); //跑步行为int eat(char *ObjectName,int l); //存放行为
};
person::person()
{strcpy(name,zhangsan);height 168.4;weight 64.2;strcpy(cell,17873432557);
}
person::person(const char *ne,float h,float w,const char *ce)
{strcpy(name,ne);height h;weight w;strcpy(cell,ce);
}
int main()
{person a; //创建一个对象执行的是没有参数的构造函数person b{jiuyue,178.7,76.6,110}; //创建一个对象执行有参数的构造函数a.run();b.run();return 0;
} 构造函数可以传递参数对类中成员进行赋值, 也可以不传递实例化对象时程序会利用函数重载自动匹配调用哪个构造函数但是析构函数不同了析构函数是不可以带参数的。 注意 在实例化对象的时候如果想要程序去匹配没有参数的构造函数时一定不要这样写 person a (); 系统会认为你这是一个函数声明不会认为你这是一个对象的实例化所以你只能是以下写法 person a ; // 或 person a {}; 构造函数初始化列表 构造函数的初始化列表是对构造函数的一种升级以下情况必须用初始化列表 1.成员对象没有默认构造函数 2.成员变量是常量 3.成员变量是引用 4.初始化基类的成员 构造函数初始化列表以一个冒号开始接着是以逗号分隔的数据成员列表每个数据成员后面跟一个放在括号中的初始化式。例如 class CExample
{public:int a;float b;
//构造函数初始化列表CExample(): a(0),b(8.8){}
//构造函数内部赋值CExample(){a0;b8.8;}
}; 上面的例子中两个构造函数的结果是一样的。上面的构造函数使用初始化列表的构造函数显式的初始化类的成员而没使用初始化列表的构造函数是对类的成员赋值并没有进行显式的初始化。 我们来看第一种情况为什么要使用构造函数初始化列表(成员对象没有默认构造函数) #include iostream
#includestring.h
using namespace std;
class A
{private:int a;char b;public:A(int x,char y){a x;b y;cout a 的构造 endl;}
};
class B
{private:A a;int c;public:B(int z,char n,int x):a(z,n){ c x;}
};
int main(int argc, char const *argv[])
{B b(1,2,3);return 0;
} 例如上面程序如果 B 类中有成员变量 A 类B 类想要在构造函数中去对 a 进行初始化赋 值如果不使用构造函数初始化列表的方式就无法做到在构造函数内部去调用 a 的构造函数去对 a 进行初始化。 再来看第二种情况和第三种情况(成员变量是常量或引用) #include iostream
#includestring.h
using namespace std;
class A
{private:int a;const int b;char c;public:A(int x,char y):b(x),c(y){a 3;//b 4; //const 常量只能在声明时初始化之后不能改变//c ? //引用只能在声明的时候进行初始化}
};
int main(int argc, char const *argv[])
{char i 1;A(4,i);return 0;
} 如上程序在类 A 中有常量成员和引用成员因为这两个成员只能在声明时进行赋值初始 化其他时候都不能对其值进行改变所以必须使用构造函数初始化列表那么最后一种就容易理解了(初始化基类的成员),因为子类无法访问基类的私有成员所以必然不可能在构造函数体中对基类成员进行初始化只能使用初始化成员列表对基类初始化例如下面程序。 #include iostream
#includestring.h
using namespace std;
class A
{private:int a;const int b;char c;public:A(int x,char y):b(x),c(y){a 3;//b 4; //const 常量只能在声明时初始化之后不能改变//c ? //引用只能在声明的时候进行初始化}
};
class B:public A
{private:int x;public:B(int a1,char b1):A(a1,b1){x 2;}
};
int main(int argc, char const *argv[])
{char i 1;B(4,i);return 0;
} 结论 其实通过上面的学习我们大概了解了构造函数初始化列表的作用了简单来说就是 int a 3;
const char c 1;
A b(2,5); 上面这种初始化方式为显性赋值因为它们是声明时就初始化了。 int a;
const char c;
A b;
a 3;
c 1 //error
b(3,5); //error 而上面这种赋值就属于隐性赋值可以看到很多东西是不允许隐性赋值的例如常量 引用类。 而对构造函数进行初始化成员列表进行初始化其实就是对类的成员进行显性赋值 临时对象 临时对象是指在函数传参或者函数返回的时候临时创建的没有名字的对象用完以后会立即销毁这种对象。 例如 #include iostream
#includestring.h
using namespace std;
class A
{private:int a;int b;public:A(int x,int y):a(x),b(y){cout 构造 endl;}~A(){cout 析构 endl;}
A fun()
{return A(a,b);
}
};
int main(int argc, char const *argv[])
{A i A(1,2);A j i.fun();return 0;
} 直接调用构造函数将产生一个临时对象。 临时对象的声明周期只有一条语句的时间。 临时对象的作用域只在一条语句中。 临时对象是 C中值得警惕的灰色地带。 类的只读成员函数 在 c中我们知道 const 可以用来指定变量为只读变量那么在 C中我们还可以使用 const 来修饰类中的成员函数例如 class A
{private:int a;int b;public:A(int x,int y):a(x),b(y){}int fun() const{//...}
}; 如上程序类中的 fun()函数被 const 修饰后那么在 fun()函数中将不能对类的成员变量进行改变。这就是 const 修饰类中成员函数的作用。 拷贝构造函数 拷贝构造函数是一种特殊的构造函数它在创建对象时 是使用同一类中之前创建的对象 来初始化新创建的对象 。拷贝构造函数通常用于 •通过使用另一个同类型的对象来初始化新创建的对象。 •复制对象把它作为参数传递给函数。 •复制对象并从函数返回这个对象。 函数形式 类名 (const 类名 ) 注意 在类中有一个默认的赋值操作容易和拷贝构造搞混淆赋值操作是当 两边都是已经初始化好的对象进行赋值时才会调用赋值函数而当用一个已经初始化好的对象去初始化另一个对象时那么另一个对象就调用的是拷贝构造函数。 如果在类中没有定义拷贝构造函数编译器会自行定义一个。如果类带有指针变量并有动态内存分配则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下 class A
{private:int a;int b;public:A(int x,int y):a(x),b(y){} //构造函数初始化列表A(const A obj) //拷贝构造函数{// 构造函数的主体}
}; 当对对象进行拷贝赋值时就会调用拷贝构造函数进行初始化赋值如 int main(int argc, char const *argv[])
{A i(1,2);A j i; //调用了拷贝构造A k(i); //调用了拷贝构造return 0;
} 省略复制 复制省略是自 C11 标准起提出的一项编译优化技术通过省略复制及移动构造函数的调用实现零复制的值传递语义。省略复制一般默认存在可以通过在编译时添加-fno-elide constructors 选项来关闭省略复制 。在以下两种情况中会出现省略复制。 1. 在变量初始化中当初始化表达式 ( 右值 ) 与变量类型为同一类型的纯右值 ( 临时量 ) 时 例如 #include iostream
#includestring.h
using namespace std;
class A
{private:char buf[16];public:A(const char *str){strcpy(buf,str);cout 构造函数 endl;}A(const A a){strcpy(this-buf,a.buf);cout 拷贝构造 endl;}
};
int main()
{A ob nihao;return 0;
} 上面是进行了省略构造后的结果那关闭省略构造呢 可以看到不进行省略复制就会执行拷贝构造函数省略复制相当于把 A ob “nihao” 变成了 A ob( “ nihao ” ); 直接将对象构造到它们本来要拷贝的存储空间 , 而不进行省略复制 A ob “nihao”相当于 A ob A(“nihao”) 2. 第二种情况是在 return 语句中操作的对象是与函数返回类型为同一类型的纯右值 ( 临时量) 时例如 #include iostream
#includestring.h
using namespace std;
class A
{private:char buf[16];public:A(const char *str){strcpy(buf,str);cout 构造函数 endl;}A(const A a){strcpy(this-buf,a.buf);cout 拷贝构造 endl;}
};
A fnn()
{return A(nihao);
}
//或
A fuu()
{A a(nihao);return a;
}
int main()
{A ob fuu();return 0;
} 上图是进行了省略复制的结果 上图是不进行省略复制的结果可以看到原本的 A ob fuu(); 在不进行省略复制的情况 下编译器会被解释为 A ob A(fuu()); this 指针 在 C 中每一个对象都能通过 this 指针来访问自己的地址。 this 指针是所有成员函数的隐含参数( 也就是所有成员函数都默认有一个隐藏的指针参数保存着对象的地址 ) 。因此在成员函数内部它可以用来指向调用对象。 友元函数没有 this 指针因为友元不是类的成员。只有成员函数才有 this 指针。静态成员函数也没有 this 指针因为静态成员函数不属于某个对象只属于类本身。 class A
{private:int a;int b;public:A(int x,int y):a(x),b(y){} //构造函数初始化列表void fun(){this-a 4; //this 就是该对象的地址(*this).b 5; //*this 就相当于对象本身}
}; 如上我们可以在成员函数中利用 this 来操作成员变量至于这个 this 是谁的地址那就要看是哪个对象了例如a.fun()那么 this 就指向 a 这个对象b.fun();那么 this 就指向 b 这个对象this 其实用处很多如下面程序 class A
{private:int a;int b;public:A(int x,int y):a(x),b(y){} //构造函数初始化列表void fun(int a,int b){//a a; //erreor ,系统会以为是形参 a 赋值给形参 a并不会改变成员变量的值//b b; //同上理this-a a;this-b b;}
}; 当参数的名字和成员的名字相同时那么就必须使用 this 去做区分了。 总之我们理解 this 是成员函数中隐藏的一个指向对象地址的一个指针就可以了就相当于原本类中的函数应该都是下面这样的 void sun ( A * this ); void fun ( int a , int b , A * this ); 每个函数中都必须有一个类指针 this当调用它时就会默认传入调用者对象的地址如 下 A a ( 1 , 2 ); a . sun ( a ); a . fun ( 1 , 2 , a ); 但是你可以理解为系统将这些东西都隐藏了。 类的静态成员函数 静态成员函数是使用 static 修饰的成员函数只能被定义一次而且要被同类的所有对象所共享它是类的一种行为与对象无关。 class person
{
public:static void func(); //只需要在类内进行声明
}; 它有如下特点 1. 静态成员函数不可以直接访问类中非静态数据成员以及非静态成员函数只能通过对象名由参数传入来访问即在类的静态成员函数类的静态方法内部不能直接访问 this 指针和对象的数据成员在类的静态成员函数类的静态方法内部只能访问类的静态数据 成员 2. 静态成员函数在类外定义时无需加 static 修饰否则出错 3. 在类外可以通过对象名以及类名来调用类的静态成员函数和变量 4. 对象和类可以直接访问静态成员函数静态成员之间在类中可以相互访问包括静态成员函数访问静态数据成员和访问静态成员函数; 5. 在类外可以通过对象名以及类名来调用类的静态成员函数静态成员函数不能访问非静态成员函数和非静态数据成员 6. 声明静态成员函数时不可同时声明为 virtual 、 const 、 volatile 函数 7. 静态函数可以使用作用域标识符直接访问无需创建任何对象就可以访问 int main(int argc, char const *argv[])
{A::fun();return 0;
} 8. 类的静态成员变量必须在类外进行初始化才能被使用否则报错例如 class A
{private:int a;int b;static int c;public:static void fun();
};
int A::c 0; //静态成员变量初始化 可以使用对象操作静态成员变量也可以使用类本身前提是静态成员变量是公有的如下程序 #include iostream
#includestring.h
using namespace std;
class A
{private:int a;int b;public:static int c;static void fun(){cout c endl;}
};
int A::c 0;
int main(int argc, char const *argv[])
{A a;a.c 0;A::c 5;a.fun();return 0;
} 友元函数和友元类(friend) 按 c的封装性来说最主要的目的就是确保数据的安全实现信息的隐藏从原则上来 说类的私有成员和保护成员在类的外部是不能直接访问的但是有一个例外这个就是友元(friend)友元就是在类的声明中用关键字 friend 修饰的函数或者类,友元授予一个函数或者一个类特权允许他们能直接访问本类的隐藏信息. 友元函数 友元函数不是类的成员函数但是仍可以访问该类的私有成员。友元函数可以是一个外部函数也可以是另一个类的成员函数。 友元函数可以访问类中的私有成员和其他数据但是访问不可直接使用数据成员需要通 过对对象进行引用所以友元函数必须有一个参数用来传递对象的地址或引用 当友元函数是全局类外函数时在类中声明的格式 friend 返回值类型 函数名(参数列表); 如下是当类外函数做友元的示例 #include iostream
#includestring.h
using namespace std;
class A; //对 A 进行超前声明不然 sun 参数找不到
int sun(int a,int b,A c);
class A
{private:int x;int y;public:A(int a,int b):x(a),y(b){}~A(){}friend int sun(int a,int b,A c);
};
int sun(int a,int b, A c)
{c.x a;c.y b;return c.xc.y;
}
int main(int argc, char const *argv[])
{A a(2,4);sun(1,2,a);return 0;
} 特别要注意的是在对函数声明时一定要对类进行超前声明因为在对函数声明中有个参数是这个类不进行超前声明函数会找不到这个类的定义。还有在友元函数在调用上同一般函数一样不必通过对对象进行引用。 当友元函数是另外一个类中的成员函数时在类中声明的格式 friend 返回值类型 类名::函数名(参数列表); 如下是当其他类的成员函数做友元的示例 #include iostream
#includestring.h
using namespace std;
class A; //对 A 进行超前声明不然 sun 参数找不到
class B
{private:int i; char j;public:B(int a,char c){i a;j c;}~B(){}int fun(A *rm);
};
class A
{private:int x;int y;public:A(int a,int b):x(a),y(b){}~A(){}friend int B::fun(A* rm); //友元
};
int B::fun(A *rm)
{i rm-x rm-y;j a;return i;
}
int main(int argc, char const *argv[])
{A a(2,4);B b(2,A);b.fun(a);return 0;
} 友元类 可以将一个类定义为另一个类的友元这样被定义为友元的类中的函数就可以访问另一个类中的所有内容了 这样是不安全的。最好的方法就是哪个需要访问就设置为友元函数即可。 当其他类是友元类时在类中声明的格式 friend 类名; 如下是当其他类做友元的示例 #include iostream
#includestring.h
using namespace std;
class A; //对 A 进行超前声明不然 sun 参数找不到
class B
{private:int i; char j;public:B(int a,char c){i a;j c;}~B(){}int fun(A a);
};
class A
{private:int x;int y;friend B;public:A(int a,int b):x(a),y(b){}~A(){}
};
int B::fun(A a)
{i a.x a.y;return i;
}
int main(int argc, char const *argv[])
{A a(2,4);B b(2,A);b.fun(a);return 0;
} 友元注意事项 1.友元关系是单向的如 类 A 声明它有一个朋友 B即 B 是 A 的朋友反过来A 不一定是 B 的朋友 2. 友元关系是不可传递的如 A 是 B 的朋友B 是 C 的朋友A 不一定是 C 的朋友 3. 一个函数可以是多个类友元函数。