473,388 Members | 1,326 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

Abstract Data Types - Separating Interface from Implementation

Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions
const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}
private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?

Cheers,

Deets
Jul 22 '05 #1
9 4604
"Anon Email" <an********@fastmail.fm> wrote...
Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely ^^^^^^^^^^^^^
I guess you mean "it's IMpossible", don't you?
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions
const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}
private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?


I am not sure what book you read on C++, but you don't need to
(actually you mustn't) declare your member functions before trying
to define them. Just throw away the declarations and keep the
definitions (which will also be declarations).

class has_definitions_inside
{
int foo()
{
return 42;
}
double bar()
{
return 3.14159;
}
}
Victor
Jul 22 '05 #2
"Anon Email" <an********@fastmail.fm> wrote in message
news:83*************************@posting.google.co m
Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions
const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}
private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?

Cheers,

Deets


You seem to be confusing implementation code and client code.

All declarations of the class object and all calls to the class member
functions are client code. Implementation code is basically code that
defines the member functions plus a class's data members. Your changes move
all the implementation code into the header file and, if anything, reduce
the separation between interface and implementation.

It should be pointed out that the most important aspect of
interface/implementation separation is not what file the code goes in. In
the most fundamental sense, a class's interface consists of its public
members. Accordingly, to maximise separation between interface and
implementation, you should minimise a class's public members. This usually
means making all data members private (or protected if absolutely necessary)
so that clients interact with class objects only through calling public
member functions. This allows you to change anything in the class except for
the signatures of the public member functions without necessitating any
change in client code.
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)

Jul 22 '05 #3
"John Carson" <do***********@datafast.net.au> wrote in message
news:3f********@usenet.per.paradox.net.au

All declarations of the class object and all calls to the class member
functions are client code.


I should have said "all calls to class member functions other than those
from other member functions are client code."
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)

Jul 22 '05 #4
Thanks guys.
You seem to be confusing implementation code and client code.


Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?
3) Is the class interface typically found in your header file?
3) Is the class implementation typically found in your source file?
4) Are abstract data types "abstract" because they are specified
separate to implementation?
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably. Is there such a thing as an
"implementation interface", as opposed to an interface?

The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."

This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html

I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.

Cheers,

Deets
Jul 22 '05 #5
Anon Email wrote:
Thanks guys.

You seem to be confusing implementation code and client code.

Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?


Those are unrelated issues. Here's how it usually works for me, when
I'm working on my own. In reality, there are often several people
involved in various steps of this process, e.g. step 1 might be done by
a manager or committee, steps 2 and 3 might be done by me, and step 4
might be done by someone assigned to help me.

1) I decide I need a program to do something, e.g. provide some
information or some service I can't easily get from my system already.

2) I write a basic, simplistic program to show the outline of what I
want to do. When the program needs to do something complicated, I
pretend I have a function or object that does the complicated bit. I
decide how I'd like to be able to call the function, what the inputs and
outputs should be. To make my skeletal program compile, I declare the
functions and classes; for example, if I need to send data over a
network, I might make up a function that looks like this:

void send_data_to_host( class Datum&, std::string const& host_name );

If I want to be able to do complicated things to the network connection,
I might define a class that looks like this:

class Packet;

class Network_Connecton
{
public:
enum Protocol { tcp, udp };

Network_Connection(
std::string const& host_name,
Protocol const& protocol =tcp );

~Network_Connection( );

void open(
std::string const& host_name,
Protocol const& protocol =tcp );

void close( ) throw( );

void send( Packet& );

void receive( Packet& );

// ... other operations ...
};

I don't define any of the functions yet, I just declare them and compile
my program to object code (with my compiler's -c flag). I keep doing
this and thinking about what sorts of functions and data structures I'd
like to have available. I work out the high-level issues, e.g. exactly
what outputs the program will provide, what inputs will be needed, how I
can break the program into discrete parts, etc.

3) I take all the made-up functions and classes I've declared and
separate them into categories, putting all the bits involving each
category into a separate ".hh" file. For example, I might find myself
with a "network.hh" file, a "user_interface.hh" file, and a "math.hh"
file. Each such file defines an *interface*. Whatever's left of the
original program (once I've moved my made-up declarations into separate
files) is called *client code*.

4) For each interface file, I write a corresponding ".cc" file that
defines all the functions I've declared. I write the definitions one at
a time. I don't worry too much about making the functions fast, I just
try to make sure that each one will provide exactly the output I wanted
when I was writing the client code. Most of the functions are
straight-forward, and I can write them pretty quickly. If a function is
taking an especially long time to write, or I think a function's
definition is getting too complicated, I do the same thing I did in step
1: I try to break the task into smaller bits, and declare new functions
to perform small parts of the function's task. The new, "helper"
functions don't need to be declared in the original interface files,
since the client code does not directly depend on them. The collection
of all these function definitions, helper functions, etc. is called the
*implementation code*. The combination of an interface file and its
corresponding implementation file is called a *module*. As I'm working
on a given module, I compile to object code now and then, so the
compiler has a chance to point out the mistakes I make as I'm working.

5) I take all the modules, and try to compile them together. At this
point, the compiler executes another program called a "linker." The
linker tries to make sure that each function and variable I used in the
client code has actually been defined in one of the modules.

6) I test the code to make sure it's right, and that I didn't make
mistakes like forgetting to release memory or file handles when they
were no longer needed. At this point, I usually wish I already had
written code to do the testing for me. (I'm trying now to get into the
habit of writing testing code before I even start writing the program.)

7) Once I'm pretty sure the program is working correctly, I start
*profiling* it to determine where it's spending its time. Usually, the
program spends most of its time in only a few of the functions. I pick
one of those functions, try to make it faster, and go back to step 5.
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?
Yes, that's the basic idea.
3) Is the class interface typically found in your header file?
Yes.
3) Is the class implementation typically found in your source file?
Both headers and implementation files are "source files."
4) Are abstract data types "abstract" because they are specified
separate to implementation?
No. An abstract class is special, in that it does not have definitions
for all of its methods. Such an undefined method is called "pure
virtual." Since the class is not completely defined, it can never be
instantiated; that's what makes it "abstract." Such a class is useful
because each class "derived" from it can provide a different
implementation of each virtual function. This feature supports a design
style called "polymorphism." To understand polymorphism, you first need
to have a basic understanding of a technique called "inheritance." See
chapter 12 of TC++PL.
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably. Is there such a thing as an
"implementation interface", as opposed to an interface?
No, although an interface file may actually contain part of the
implementation of a module. Bjarne is not using the terms
interchangeably; please feel free to post any quotes from the book that
you find confusing.
The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."

This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html
That's a load of garbage. C++ provides better support for safely
separating interface from implementation than any other language I know.
In fact, that single fact is probably the reason C++ is my favorite
language.

The first paragraph you listed does have a shred of truth: When a C++
module (or any client code) is compiled, the interfaces of all
supporting modules must be available. This differs somewhat from
interpreted languages like Java that support a feature called
"reflection." However, the compiler does *not* need to know about all
files in the project, thanks to "dynamic linking."

The second paragraph says that the data members of a class must be
included in the interface file. This is certainly possible, and is
often done for "concrete" data types, for which performance is critical.
For most classes, though, it is absolutely not necessary. Only the
methods of the interface must be specified in the interface file.
Classes implementing the interface are simply derived from the interface
class, and all the details are hidden in implementation files.
I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.

Cheers,

Deets


I hope I've managed to clear some of this up; I know it's confusing.
C++ supports a lot of different design styles, and I think Bjarne tries
to show in his book how these styles differ, and how they can be used
together. Really, there is no substitute for writing your own programs
to find out why all these different techniques are useful, and how an
interface differs from an implementation. If you really want to
understand how client code differs from library code, try writing your
own library of classes and functions to make some difficult task seem
easy. Then, try writing programs that use your library.

Good luck, and please feel free to criticize or question any part of the
above explanation.

-Jeff

Jul 22 '05 #6
"Anon Email" <an********@fastmail.fm> wrote in message
news:83*************************@posting.google.co m
Thanks guys.
You seem to be confusing implementation code and client code.
Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?


These definitions are not laid down as part of any standard. They are a
convenient shorthand with a somewhat flexible meaning depending on context.

Client code of class X might belong to some other class Y or might not
belong to any class. The important feature is that it doesn't belong to
class X.

Note that if you have a hierarchy of classes, then the calling of members of
one class by members of another class in the same hierarchy would not
normally be termed "client code" (particularly if such function calls are an
integrated part of the design of the hierarchy), but you might still
occasionally find it called "client code".
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?
No. The aim is to expose as little of the class as is consistent with
allowing the clients of the class to make use of the functionality it
offers. Information about a class is supplied to clients on a "need to know"
basis. This is for three reasons:

a) It simplifies things for the client; there is less to understand,
b) It makes the implementation more robust because clients aren't free to
change variables and thereby cause problems elsewhere,
c) It makes for greater flexibility. If clients know how a class works, then
they will seek to make use of that in their code and the client code will
stop working if the way the class works changes. By minimising what clients
know about the way the class works, you minimise the risk that changing
something about the way a class works will break client code.
3) Is the class interface typically found in your header file?
Yes.
3) Is the class implementation typically found in your source file?
[you have two 3s] .h and .cpp files are both source files. The
implementation is typically found in the .cpp file.
4) Are abstract data types "abstract" because they are specified
separate to implementation?
Yes. The idea of "abstract data types" predates C++. Clients know what an
abstract data type can do for them, but don't know how it is accomplished.

Note that you will also find references to "abstract classes", which are
classes that contain at least one pure virtual function. This is a C++
language construct and is distinct from the more general concept of an
abstract data type.
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably.
Is there such a thing as an
"implementation interface", as opposed to an interface?

If you start reading at p314, then it should be clear that Stroustrup
distinguishes interface and implementation quite sharply. Stroustrup is
discussing a complicated case in which the program code needs to be able to
work in multiple environments and where there is a complicated inheritance
hierarchy. He occasionally uses the word "implementation" somewhat flexibly,
e.g., by "implementation detail" he may mean "implementation detail in an
ideal design" as opposed to an implementation detail of the current design.
Like I said, words like "implementation" are not laid down in any standard
and may be used somewhat differently in different contexts.

The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."
This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html

I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.


His ideal situation is one where the private members of the class would not
need to be in the header file. If you really care about this, there is a
well known workaround whereby you can omit private members from the header
file by having the header file contain just a pointer to data members that
are stored in the .cpp file. This is know as the "pimpl idiom" (short for
"pointer to implementation"). See, e.g.,

http://c2.com/cgi/wiki?PimplIdiom

or do a Google search.
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)

Jul 22 '05 #7
Correction:
4) Are abstract data types "abstract" because they are specified
separate to implementation?

I see now that you were asking about abstract data types, not abstract
classes. Abstract, in the sense you used it, means only that the
implementation is hidden from the user. This usually means an extra
level of redirection is needed, and the redirection is usually through a
pointer. One popular approach is to have a *factory* or static method
return a pointer to a class implementing the interface, and another is
the "pimpl" method John Carson already mentioned.
No. An abstract class is special, in that it does not have definitions
for all of its methods. Such an undefined method is called "pure
virtual." Since the class is not completely defined, it can never be
instantiated; that's what makes it "abstract." Such a class is useful
because each class "derived" from it can provide a different
implementation of each virtual function. This feature supports a design
style called "polymorphism." To understand polymorphism, you first need
to have a basic understanding of a technique called "inheritance." See
chapter 12 of TC++PL.


Jul 22 '05 #8
Thanks Victor, John and Jeff!

For the most part, your explanations have clarified everything. Most
of the remaining confusion is related to areas that I've only touched
upon in C++, and I won't bother you with that right now. I do,
however, have a couple more niggly questions:

1) To Jeff:
Whatever's left of the
original program (once I've moved my made-up declarations into separate
files) is called *client code*.
This may be a dumb question, but I'll ask anyway. Your client code
ends up in a .cpp file, right? And it has no corresponding header
file, unlike all your implementation code files? I gather that the
client code is where your main function lies?

2) Is your use of ".hh" for header files your own convention?

3) To Victor:
I am not sure what book you read on C++, but you don't need to
(actually you mustn't) declare your member functions before trying
to define them. Just throw away the declarations and keep the
definitions (which will also be declarations).


Do you mean that you shouldn't declare member functions where no
member function definition exists? I gather that this is because the
declarations take up space? Jeff declares a number of functions before
defining them in his implementation code...hence the question.

Cheers, and thanks for such detailed and thorough answers,

Deets
Jul 22 '05 #9
Anon Email wrote:
Thanks Victor, John and Jeff!

For the most part, your explanations have clarified everything. Most
of the remaining confusion is related to areas that I've only touched
upon in C++, and I won't bother you with that right now. I do,
however, have a couple more niggly questions:

1) To Jeff:

Whatever's left of the
original program (once I've moved my made-up declarations into separate
files) is called *client code*.

This may be a dumb question, but I'll ask anyway. Your client code
ends up in a .cpp file, right? And it has no corresponding header
file, unlike all your implementation code files? I gather that the
client code is where your main function lies?


That depends. :) In the example I listed, yes, you're correct that no
header is needed. However, sometimes your program has to fit into a
larger framework; e.g., when you are writing an OS kernel extension, or
a library for use by other people. In such cases, you have to provide a
header for those people (the "clients" of your code) to use.
2) Is your use of ".hh" for header files your own convention?
I "invented" it myself, but I'm sure I wasn't the first; I've since seen
it in other peoples' code. It makes a nice parallel to ".cc", which I
think was Bjarne's old extension when C++ was implemented mainly by the
preprocessor. It's supposed to stand for "C With Classes." Anyway, I
would have liked to use .h and .c, but they confuse certain compilers
and editors.
Cheers, and thanks for such detailed and thorough answers,

Deets


I'm very glad they were of use! :)

Thanks,
Jeff

Jul 22 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: phl | last post by:
hi, I am kind of confused aobut interfaces and abstract classes. In short as I understand it, an interface is like a contract between the class and the interface, so that certain funtions must...
18
by: Bradley | last post by:
I'm trying to determine if there's a general rule for when an Interface should used vs. an Abstract Class. Is there any design advantage to using one or the other? Brad
1
by: D Witherspoon | last post by:
Coming up with a scenario here. For example there is the standard .NET MailMessage class. I am creating a project (let's call it CommonBase) that has the following 2 classes ...
6
by: Alden Pierre | last post by:
Hello, http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7 As per the link above it's wise to have a virtual deconstructor when creating an abstract class. Here is when I'm...
7
by: jason | last post by:
In the microsoft starter kit Time Tracker application, the data access layer code consist of three cs files. DataAccessHelper.cs DataAcess.cs SQLDataAccessLayer.cs DataAcccessHelper appears...
0
by: mailforpr | last post by:
Hi. Let me introduce an iterator to you, the so-called "Abstract Iterator" I developed the other day. I actually have no idea if there's another "Abstract Iterator" out there, as I have never...
4
by: N.RATNAKAR | last post by:
hai, what is abstract class and abstract method
5
by: sam_cit | last post by:
Hi Everyone, We know that objects of Abstract class can't be created and functions of abstract class have to be overriden by the child class, so this makes me think as to what is the use of...
3
by: jacob navia | last post by:
Abstract: Continuing the discussion about abstract data types, in this discussion group, a string collection data type is presented, patterned after the collection in C# and similar languages...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.