2022.3.22
类成员,类的组合,友元
-
常对象只能调用它的常成员函数,而不能调用普通的成员
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n; public: int m; Sample(int i,int j){ m=i; n=j; } void setvalue(int i){ n=i; } void disply() {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } }; int main() {const Sample a(10,20); a.setvalue(40); a.m=30; a.disply(); return 0;}
所以setvalue()方法不能使用
同时,常对象即便是public数据成员也不能直接修改,
-
常函数的说明格式:
类型说明符 函数名(参数表)const;
声明带const , 使用不需要,同时,常成员函数不能更新对象的数据成员的值
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n; public: int m; Sample(int i,int j){ m=i; n=j; } void setvalue(int i){ n=i; } void disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } }; int main() {const Sample a(10,20); a.disply(); return 0;}
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n; public: int m; Sample(int i,int j){ m=i; n=j; } //void setvalue(int i){ n=i; } void disply() ; void disply() const ; }; void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } int main() {const Sample a(10,20); a.disply(); Sample b (20,30); b.disply(); return 0;}
注意下,class最后花括号后面要加个分号
-
使用const说明的数据成员称为常数据成员。
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化, 而不能采用在函数中直接赋值的方法#include<iostream> //例3.40-2 using namespace std; class Sample{ private: const int n,a,b; public: const int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } int main() {const Sample a(10,20,30,40); a.disply(); Sample b (10,90,20,30); b.disply(); return 0;}
才发现,c++参数列表貌似就是java中this.a=a这个操作,像下面三种,第一种完全达到目的,第二种第三种都得到垃圾值
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: const int n,a,b; public: const int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } int main() {const Sample a(10,20,30,40); a.disply(); Sample b (10,90,20,30); b.disply(); return 0;}
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: const int n,a,b; public: const int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m) { n=n; m=m; a=a; b=b; } void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } int main() {const Sample a(10,20,30,40); a.disply(); Sample b (10,90,20,30); b.disply(); return 0;}
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n,a,b; public: int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m) { n=n; m=m; } void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } int main() {const Sample a(10,20,30,40); a.disply(); Sample b (10,90,20,30); b.disply(); return 0;}
-
总结一下,
普通成员函数 常成员函数 普通数据成员 可以访问,也可以改变值 可以访问,但不可以改变值 常数据成员 可以访问,但不可以改变值 可以访问,但不可以改变值 常对象的数据成员 不允许访问和改变值 可以访问,但不可以改变值 -
定义静态数据成员的格式如下:
static 数据类型 数据成员名;
#include<iostream> //例3.40-2 using namespace std; class Sample{ static int c; private: int n,a,b; public: int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; int Sample:: c =79898; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; cout<<"c="<<c<<endl; } int main() {const Sample a(10,20,30,40); a.disply(); Sample b (10,90,20,30); b.disply(); return 0;}
-
静态数据成员的初始化要在main()函数之前,类定义之外
-
值得注意,下面这种写法没什么问题(我个人觉得挺离谱的),因为对象的声明的
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n,a,b; public: static int c; int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; cout<<"c="<<c<<endl; } int Sample:: c =79898; const Sample a(10,20,30,40); int main() { cout<<Sample::c; a.disply(); Sample b (10,90,20,30); b.disply(); return 0; }
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n,a,b; public: static int c; int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; }; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; cout<<"c="<<c<<endl; } int Sample:: c =7000000; const Sample a(10,20,30,40); int main() { Sample:: c =79898; cout<<Sample::c; a.disply(); Sample b (10,90,20,30); b.disply(); return 0; }
我稍微修改了下,静态数据成员能这么写估计是因为public了,所以声明对象以后又将c的值修改了下,不过这种延后感觉有点不太协调.
-
若静态成员函数需要访问非静态成员,静态成员函数只能通过对象名(对象指针或引用)访问该对象的非静态成员
这个其实挺好理解的,因为静态成员函数在对象声明前存在,所以必须得有引用或者指针或者对象才可以调用函数.(注意下,对象我指的是直接在函数里初始化得到的一个,而指针引用我指的其实是在形参列表处的)
-
如何给组合类中的对象成员初始化
class X { 类名1 对象成员名1; 类名2 对象成员名2; … 类名n 对象成员名n; };
X∷X(参数表0):对象成员名1(参数表1),对象成员名2 (参数表2),…,对象成员名n(参数表n) { 类X的构造函数体 }
表现形式
class A { //.. .. }; class B { //.. .. }; class C { //.. .. }; class D { A a; B b; C c; public: D(参数表0):a(参数表1),b(参数表2),c(参数表3) { // …构造函数体 } } ;
-
如何用友元函数
#include<iostream> //例3.40-2 using namespace std; class Sample{ private: int n,a,b; public: static int c; int m; //void setvalue(int i){ n=i; } Sample(int n,int a,int b,int m); void disply() ; void disply() const ; friend void fun(Sample &w); }; Sample::Sample(int n, int a, int b, int m):n(n),a(a),b(b),m(m) {} void fun(Sample & w){ cout<<w.c; } void Sample::disply() { cout<<"another"; } void Sample::disply() const {cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; cout<<"c="<<c<<endl; } int Sample:: c =79898; int main() { Sample b (10,90,20,30); fun(b); return 0; }
注意下,友元函数不能用const变成常成员函数,也就是友元函数不能处理常对象
友元函数最大的特点就是,不需要对象或者类的格式就可以直接使用,比较像c语言,至于破坏封装,我其实我现在还没感觉到
一个函数可以是多个类的友元函数。当一个函数需要访问多个类时,友元函数非常有用,不过这样会非常混乱,改bug可以玩死你,修改个数据也会死的挺惨的
-
将其它类成员函数声明为本类友元函数
一个类的成员函数也可以作为另一个类的友元,这种成员函数称为友元成员函数。
定义友元成员函数目的:使两个或多个类相互合作、协调工作,完成某一任务。成员函数可以访问自己类的对象,不需要引用,然后访问别的类的对象时,则需要
-
友元类的说明方法是在另一个类声明中加入语句:
friend 类名;
class Y { … }; class X { … friend Y; … };
友元类的一个特点就是Y中的所有函数对于X都是友元函数
-
string类的直接复制是深拷贝,复制的字符串修改并不影响前面被拷贝的字符串
#include <string> #include <iostream> using namespace std; int main(){ std::string a ="abcd"; std::string b =a; cout<<&a<<endl; cout<<&b<<endl; std::cout<<a<<std::endl; cout<<b<<endl; b[0]='h'; cout<<&a<<endl; cout<<&b<<endl; cout<<a<<endl; cout<<b<<endl; }
-
一段有意思的代码
#include <string> #include <iostream> using namespace std; class A { private: int a; public: A(int a); void display(); }; A::A(int a) :a(a){ cout<<"first"<<endl; } void A::display() { cout<<a; } int main(){ A a =10; A b = a; a.display(); b.display(); return 0; }