I am making my first steps in learning OOP . And here is the first problem which I can't solve.
The max function in this class should return the maximum of two numbers . I want to keep the numbers in the private scope and the functions in the public scope . But when I want to use variables from struct data{} in the public scope the compiler says that the variables are not declared . Please tell me why I get these errors .
class myclass{
private:
struct data{
int q ;
int w;
};
public:
void get(int a, int b){
struct data = {a , b}; // here I want to pass the variables to data struct
}
int max (){ // this function returns the biggest number
if(q>w)
return q;
else
return w;
}
};
struct data{
int q ;
int w;
};
only declares a type, not an object, so there are no q and w members anywhere inside your class instances. You need the declare an instance of the struct:
struct {
int q;
int w;
} data;
Then, you can write max as:
int max()
{
if (data.q > data.w)
return data.q;
else
return data.w;
}
(I've no idea what your get method is supposed to do, so I have no replacement for that.)
In C++ "class" and "struct" are close to being synonymous (the same thing). The ONLY difference is that a "struct" defaults to being "public" accessibility while a "class" defaults to private.
Once you understand this, it should become obvious that what you are doing is defining a sub-type within your class.
class myclass {
private: // <- not required, you already said that by saying "class".
struct data {
// <-- this is a class definition with "public:" just here.
...
};
};
C++ allows you to nest class/structure definitions so that you can, for example, create structures that marshal parameters or return values.
class Database {
class Result { ... };
};
...
class Exam {
class Result { ... };
};
These two result classes avoid namespace collision, by being Database::Result and Exam::Result instead of just "Result".
However - these are only definitions. They do not - as shown - have any effect on the outlying class, that is: they aren't being used to add a member to the class.
Your code:
class myclass{
private:
struct data{ // <-- this is a TYPE declaration, struct myclass::data
int q ; //
int w; //
}; // <-- no member name here so does not affect myclass itself.
public:
void get(int a, int b){
struct data = {a , b}; // here I want to pass the variables to data struct
}
int max (){ // this function returns the biggest number
if(q>w)
return q;
else
return w;
}
};
Declares a type "myclass::data" but does not add a member of type "myclass::data" to the class. The line "struct data = " is illegal, you're trying to assign values to a TYPE.
It should probably be written as
class MyClass {
int m_q;
int m_w;
public:
void set(int q, int w) {
m_q = q;
m_w = w;
}
int max() const {
return (m_q > m_w) ? m_q : m_w;
// or #include <algorithm> and return std::max(m_q, m_w);
}
};
You only need to hoist q & w into a struct if you are going to reuse that structural definition outside the confines of the class, e.g. in derived or parallel classes where you may want to add more of the same type of thing, in which case, you could perhaps do the following, but if you do it this exact way you'll eventually kick yourself for breaking encapsulation:
class MyClass {
public:
struct Data {
int m_q;
int m_w;
};
private:
Data m_data;
void set(int q, int w) {
m_data.m_q = q;
m_data.m_w = w;
}
int max() const {
return (m_data.m_q > m_data.m_w) ? m_data.m_q : m_data.m_w;
}
};
A better way, if this coupling of members needs to be externally visible to some degree would be:
class MyClass {
public:
class Data {
int m_q;
int m_w;
public:
Data() : m_q(0), m_w(0) {}
Data(int q, int w) : m_q(0), m_w(0) {}
void set(int q, int w) {
m_q = w;
m_w = w;
}
int q() const { return m_q; }
int w() const { return m_w; }
int max() const { return (m_q > m_w) ? m_q : m_w;
};
private:
Data m_data;
public:
MyClass() : m_data() {} // or = default
MyClass(int q, int w) : m_data(q, w) {}
MyClass(const Data& data) : m_data(data) {}
// Read-only access
const Data& data() const { return m_data; }
// To allow write access, e.g. for set:
Data& data() { return m_data; }
};
It's kinda overkill for such a simple case, but welcome to C++: the boilerplate language.
You have defined the structure but there is no object of that type. You should declare an object and you will not get any error.
class myclass{
private:
struct data{
int q ;
int w;
}var;
public:
void get(int a, int b){
var .q= a;
var.w=b; // here I want to pass the variables to data struct
}
int max (){ // this function returns the biggest number
if(var.q>var.w)
return var.q;
else
return var.w;
}
};
Related
I am working on a plugin that runs inside a host program against a proprietary PDK. At times there will be breaking changes in the PDK, so my code uses wrapper classes that allow it to work with more than one version of the host while encapsulating the changes from version to version.
Here is a very simplified example that illustrates the kind of issue I would like to address. Of course, I'm dealing with many more members that 2.
struct DataV1 // I cannot modify this
{
int a;
float b;
};
struct DataV2 // I cannot modify this
{
float b;
int a;
long c;
};
class DataWrapper // my class
{
private:
bool _forV1; // determined at run-time
DataV1 _dataV1;
DataV2 _dataV2;
public:
DataWrapper(); // initializes _forV1
int GetA() const;
void SetA(int value);
float GetB() const;
void SetB(float value);
long GetC() const { return _dataV2.c } // only exists in v2
void SetC(long value) { _dataV2.c = value; } // only exists in v2
};
I would like to avoid duplicating in every getter and setter the logic that chooses the member from one version of the struct or the other. Note that while the order of members is rearranged, the types and member names are the same. I came up with this macro:
#define DATA_ACCESS(MEMBER) const_cast<decltype(_dataV1.MEMBER)&>(([&]() -> const decltype(_dataV1.MEMBER)& \
{ return (_forV1) ? _dataV1.MEMBER : _dataV2.MEMBER; })())
This allows for a somewhat elegant implementation of the property accessor functons:
int GetA() const { return DATA_ACCESS(a); }
void SetA(int value) { DATA_ACCESS(a) = value; }
float GetB() const { return DATA_ACCESS(b); }
void SetB(float value) { DATA_ACCESS(b) = value; }
I am posting this question to see if anyone has a better idea, especially an idea that doesn't involve a macro. Thanks.
With std::variant, you might do something like:
class DataWrapper // my class
{
private:
std::variant<DataV1, DataV2> data;
public:
DataWrapper(); // initializes _forV1
int GetA() const { return std::visit([](auto& arg){ return arg.a; }, data); }
void SetA(int a) const { std::visit([&a](auto& arg){ arg.a = a; }, data); }
// ...
};
I want to create a class which behaves a certain way - e.g. spits out certain values from a function double getValue(const int& x) const - based on a "type" that was passed into its constructor. Right now I have two methods:
Store the passed-in "type" and then evaluate a switch statement in getValue each time it is called in order to decide which implementation to use.
Use a switch statement on the passed-in "type" (in the constructor) to create an internal object that represents the desired implementation. So no switch required anymore in getValue itself.
Method 1 "appears" inefficient as switch is called every time I call getValue. Method 2 seems somewhat clunky as I need to utilise <memory> and it also makes copying/assigning my class non-trivial.
Are there any other cleaner methods to tackle a problem like this?
Code Example:
#include <memory>
enum class ImplType { Simple1, Simple2 /* more cases */ };
class MyClass1
{
private:
const ImplType implType;
public:
MyClass1(const ImplType& implType) : implType(implType) { }
double getValue(const int& x) const
{
switch (implType)
{
case ImplType::Simple1: return 1; /* some implemention */
case ImplType::Simple2: return 2; /* some implemention */
}
}
};
class MyClass2
{
private:
struct Impl { virtual double getValue(const int& x) const = 0; };
struct ImplSimple1 : Impl { double getValue(const int& x) const override { return 1; /* some implemention */ } };
struct ImplSimple2 : Impl { double getValue(const int& x) const override { return 2; /* some implemention */ } };
const std::unique_ptr<Impl> impl;
public:
MyClass2(const ImplType& implType) : impl(std::move(createImplPtr(implType))) { }
static std::unique_ptr<Impl> createImplPtr(const ImplType& implType)
{
switch (implType)
{
case ImplType::Simple1: return std::make_unique<ImplSimple1>();
case ImplType::Simple2: return std::make_unique<ImplSimple2>();
}
}
double getValue(const int& x) const { return impl->getValue(x); }
};
int main()
{
MyClass1 my1(ImplType::Simple1);
MyClass2 my2(ImplType::Simple1);
return 0;
}
Your code is basically mimicing a virtual method (sloppy speaking: same interface but implementation is chosen at runtime), hence your code can be much cleaner if you actually do use a virtual method:
#include <memory>
struct base {
virtual double getValue(const int& x) const = 0;
};
struct impl1 : base {
double getValue(const int& x) { return 1.0; }
};
struct impl2 : base {
double getValue(const int& x) { return 2.0; }
};
// ... maybe more...
enum select { impl1s, impl2s };
base* make_impl( select s) {
if (s == impl1s) return new impl1();
if (s == impl2s) return new impl2();
}
int main() {
std::shared_ptr<base> x{ make_impl(impl1) };
}
Not sure if this is what you are looking for. By the way, using <memory> should not make you feel "clunky", but instead you should feel proud that we have such awesome tools in c++ ;).
EDIT: If you dont want the user to work with (smart-)pointers then wrap the above in just another class:
struct foo {
shared_ptr<base> impl;
foo( select s) : impl( make_impl(s) ) {}
double getValue(const int& x) { return impl.getValue(x); }
};
now a user can do
int main() {
auto f1 { impl1s };
auto f2 { impl2s };
f1.getValue(1);
f2.getValue(2);
}
If you have a closed set of types you can choose from, you want std::variant:
using MyClass = std::variant<MyClass1, MyClass2, MyClass3, /* ... */>;
It doesn't use dynamic allocation - it's basically a type-safe modern alternative to union.
More object-oriented approach:
class Interface
{
public:
virtual int getValue() = 0;
};
class GetValueImplementation1 : public Interface
{
public:
int getValue() {return 1;}
};
class GetValueImplementation2 : public Interface
{
public:
int getValue() {return 2;}
};
class GeneralClass
{
public:
GeneralClass(Interface *interface) : interface(interface) {}
~GeneralClass()
{
if (interface)
delete interface;
}
int getValue() { return interface->getValue(); }
private:
Interface *interface;
};
So, in this case you can use it without any pointers:
int main()
{
GeneralClass obj1(new GetValueImplementation1());
GeneralClass obj2(new GetValueImplementation2());
cout << obj1.getValue() << " " << obj2.getValue();
return 0;
}
The output will be:
1 2
But in the case you should be careful with null pointers or use smart ones inside GeneralClass.
I'm trying to design a piece of code that entails the use of an algorithm. The algorithm should be easily replaceable by someone else in the future. So in my LargeClass there has to be a way to invoke a specific algorithm.
I provided some example code below. My idea was to make an interface class IAlgorithm so that you have to provide an implementation yourself. I thought you could initialize it to which ever derived class you wanted in the constructor of the LargeClass. However the below code doesn't compile in VS2015 because IAlgorithm: cannot instantiate abstract class
My question: How should I design this in order to get the result I want?
Thanks in advance!
Algorithm.h
class IAlgorithm
{
protected:
virtual int Algorithm(int, int) = 0;
};
class algo1 : public IAlgorithm
{
public:
virtual int Algorithm(int, int);
};
class algo2 : public IAlgorithm
{
public:
virtual int Algorithm(int, int);
};
Algorithm.cpp
#include "Algorithm.h"
int algo1::Algorithm(const int a, const int b)
{
// Do something
}
int algo2::Algorithm(const int a, const int b)
{
// Do something
}
Source.cpp
#include "Algorithm.h"
class LargeClass
{
private:
IAlgorithm algo;
};
int main()
{
}
My first thoughts on this would be, why use such a primitive interface?
OK, we have a requirement that some process needs an algorithm sent into it. This algorithm must be polymorphic, it must take two ints and return an int.
All well and good. There is already a construct for this in the standard library. It's call a std::function. This is a wrapper around any function object with a compatible interface.
example:
#include <functional>
#include <iostream>
class LargeClass
{
public:
using algorithm_type = std::function<int(int,int)>;
LargeClass(algorithm_type algo)
: _algo(std::move(algo))
{}
int apply(int x, int y) {
return _algo(x,y);
}
private:
algorithm_type _algo;
};
int test(LargeClass&& lc) {
return lc.apply(5,5);
}
int divide(int x, int y) { return x / y; }
int main()
{
// use a lambda
std::cout << test(LargeClass{ [](auto x,auto y){ return x + y; } });
// use a function object
std::cout << test(LargeClass{ std::plus<>() } );
// use a free function
std::cout << test(LargeClass{ divide } );
// use a function object
struct foo_type {
int operator()(int x, int y) const {
return x * 2 + y;
}
} foo;
std::cout << test(LargeClass{ foo_type() } );
std::cout << test(LargeClass{ foo } );
}
I'm coming to C++ from C# and const-correctness is still new to me. In C# I could declare a property like this:
class Type
{
public readonly int x;
public Type(int y)
{
x = y;
}
}
This would ensure that x was only set during initialization. I would like to do something similar in C++. The best I can come up with though is:
class Type
{
private:
int _x;
public:
Type(int y) { _x = y; }
int get_x() { return _x; }
};
Is there a better way to do this? Even better: Can I do this with a struct? The type I have in mind is really just a collection of data, with no logic, so a struct would be better if I could guarantee that its values are set only during initialization.
There is a const modifier:
class Type
{
private:
const int _x;
int j;
public:
Type(int y):_x(y) { j = 5; }
int get_x() { return _x; }
// disable changing the object through assignment
Type& operator=(const Type&) = delete;
};
Note that you need to initialize constant in the constructor initialization list. Other variables you can also initialize in the constructor body.
About your second question, yes, you can do something like this:
struct Type
{
const int x;
const int y;
Type(int vx, int vy): x(vx), y(vy){}
// disable changing the object through assignment
Type& operator=(const Type&) = delete;
};
Rather than a collection of constants, you could have a constant collection. The property of being constant seems to pertain to your use case, not the data model itself. Like so:
struct extent { int width; int height; };
const extent e { 20, 30 };
It's possible to have specifically constant data members of a class, but then you need to write a constructor to initialize it:
struct Foo
{
const int x;
int & y;
int z;
Foo(int a, int & b) : x(a + b), y(b), z(b - a) { }
};
(The example also shows another type of data member that needs to be initialized: references.)
Of course, structs and classes are the same thing.
You can initialize class const members with constructor. If you need add some other logic in constructor, but in .cpp file not in .h, you can create a private method and call it in constructor.
File.h
class Example
{
private:
const int constantMember1;
const int constantMember2;
const int constantMember3;
void Init();
public:
Example(int a, int b) :constantMember1(a), constantMember2(b), constantMember3(a + b) {
//Initialization
Init();
};
};
File.cpp
void Init()
{
//Some Logic intialization
}
This is not exactly answering the question asked, but if you wanted to have the simplicity of directly accessing member variables in a struct without getters, but wanted to ensure that nobody could modify the values, you could do something like this:
#include <iostream>
using namespace std;
class TypeFriend;
struct Type
{
const int &x;
const int y;
Type (int vx, int vy):x (_x), y (vy), _x (vx)
{
}
private:
friend class TypeFriend;
int _x;
};
struct TypeFriend
{
TypeFriend (Type & t):_t (t)
{
}
void setX (int newX)
{
_t._x = newX;
}
private:
Type & _t;
};
int main ()
{
Type t (1, 2);
TypeFriend tf (t);
cout << t.x << "," << t.y << endl;
// t.x = 6; // error: assignment of read-only location ‘t.Type::x’
// cout<<t.x << ","<<t.y<<endl;
tf.setX (5);
cout << t.x << "," << t.y << endl;
return 0;
}
The result of running this is:
1,2
5,2
Type::x cannot be modified externally, so it is read-only, but via TypeFriend it can be changed. This can be useful if you wanted to expose a simple interface of direct member access for reading, but wanted to restrict how those members could be changed.
Consider the following class:
class A {
const int arr[2];
public:
A() { }
};
Is it possible to initialize arr from the constructor initializer list or in any other way than on the line where it is declared (i.e. const int arr[2] = {1,2};)?
Note that I'm interested in methods that work with C++98!
By wrapping them in a struct, e.g.:
class A
{
struct Data
{
int arr[2];
};
Data const arr;
public:
A() : arr( someOtherStruct ) {}
};
This does mean that to access the data, you'd have to write arr.arr.
It's possible to avoid that by inheriting from the struct:
struct PrivateDataForA
{
int arr[2];
};
class A : private PrivateDataForA
{
public:
A() : PrivateDataForA( someOtherStruct ) {}
};
This does make the name of the struct visible outside of the class
(which might be an advantage—client code could pass you one as an
argument).
If you don't have an instance of the struct handy, say because you want
to fill it with values calculated from arguments to the constructor, you
can use a static member function:
class A : private PrivateDataForA
{
static PrivateDataForA createInitializer( int a, int b );
public:
A( int a, int b ) : PrivateDataForA( createInitializer( a, b ) )
{
}
};
For the OP’s concrete example:
#include <iostream>
#include <stddef.h>
typedef ptrdiff_t Size;
typedef Size Index;
template< class Element, Size n >
struct Array{ Element elem[n]; };
class A {
Array<int, 2> const arr_; // const int arr[2];
A& operator=( A const& ); // No such.
static Array<int, 2> const& oneAndTwo()
{
static Array<int, 2> const a = {1, 2};
return a;
}
public:
A(): arr_( oneAndTwo() ) {}
int at( Index i ) const { return arr_.elem[i]; }
};
int main()
{
using namespace std;
A o;
for( int i = 0; i < 2; ++i )
{
cout << o.at( i ) << endl;
}
}
Initializing array elements to non-zero values requires C++11 support.
In C++03, it's only possible to value-initialize your array, resulting in each element's value being 0:
class A {
const int arr[2];
public:
A() : arr() { }
};
For the relevant C++03 standardese, see this question and answer:
How can i use member initialization list to initialize it?
(I'm going to assume that by C++98 you mean not C++11, i.e. that C++03 is acceptable. If this assumption is wrong, please say so.)
No. It's not.